summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-11-09 10:55:05 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2018-11-09 10:55:05 +0100
commit227426f16163d3721fee82650980aae0eef01375 (patch)
treea64101906c15b814ec942468e88875ce8160e45d
parentc024f90f5dd5604d3f82dbbc055fd88a69d59187 (diff)
parentac7324a0ed12a67fc836b383388f2562d32e55ed (diff)
downloadbarebox-227426f16163d3721fee82650980aae0eef01375.tar.gz
barebox-227426f16163d3721fee82650980aae0eef01375.tar.xz
Merge branch 'for-next/net-switch-mv88e6xxx'
-rw-r--r--arch/arm/include/asm/system.h2
-rw-r--r--arch/arm/mach-imx/Kconfig12
-rw-r--r--arch/arm/mach-imx/Makefile1
-rw-r--r--arch/arm/mach-imx/iim.c2
-rw-r--r--arch/arm/mach-imx/include/mach/devices-imx51.h2
-rw-r--r--arch/arm/mach-imx/include/mach/devices-imx53.h2
-rw-r--r--arch/arm/mach-mxs/include/mach/devices.h2
-rw-r--r--arch/arm/mach-mxs/ocotp.c2
-rw-r--r--arch/sandbox/board/console.c2
-rw-r--r--common/console.c4
-rw-r--r--common/state/state.c2
-rw-r--r--drivers/aiodev/core.c4
-rw-r--r--drivers/aiodev/imx_thermal.c1
-rw-r--r--drivers/aiodev/qoriq_thermal.c1
-rw-r--r--drivers/amba/bus.c2
-rw-r--r--drivers/ata/disk_ata_drive.c4
-rw-r--r--drivers/base/bus.c2
-rw-r--r--drivers/base/driver.c45
-rw-r--r--drivers/base/resource.c2
-rw-r--r--drivers/clocksource/Kconfig10
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/arm_global_timer.c113
-rw-r--r--drivers/clocksource/timer-imx-gpt.c (renamed from arch/arm/mach-imx/clocksource.c)0
-rw-r--r--drivers/efi/efi-device.c2
-rw-r--r--drivers/firmware/socfpga.c2
-rw-r--r--drivers/i2c/i2c.c4
-rw-r--r--drivers/mci/mci-core.c4
-rw-r--r--drivers/mtd/core.c2
-rw-r--r--drivers/mtd/spi-nor/cadence-quadspi.c2
-rw-r--r--drivers/mtd/ubi/build.c2
-rw-r--r--drivers/mtd/ubi/vmt.c4
-rw-r--r--drivers/net/cpsw.c2
-rw-r--r--drivers/net/e1000/eeprom.c2
-rw-r--r--drivers/net/orion-gbe.c2
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/mdio_bus.c27
-rw-r--r--drivers/net/phy/mv88e6xxx/Makefile5
-rw-r--r--drivers/net/phy/mv88e6xxx/chip.c913
-rw-r--r--drivers/net/phy/mv88e6xxx/chip.h142
-rw-r--r--drivers/net/phy/mv88e6xxx/global2.c389
-rw-r--r--drivers/net/phy/mv88e6xxx/global2.h70
-rw-r--r--drivers/net/phy/mv88e6xxx/port.c663
-rw-r--r--drivers/net/phy/mv88e6xxx/port.h137
-rw-r--r--drivers/net/phy/phy.c15
-rw-r--r--drivers/nvmem/core.c2
-rw-r--r--drivers/nvmem/ocotp.c2
-rw-r--r--drivers/of/address.c4
-rw-r--r--drivers/of/platform.c80
-rw-r--r--drivers/pci/bus.c3
-rw-r--r--drivers/phy/phy-core.c2
-rw-r--r--drivers/pwm/core.c2
-rw-r--r--drivers/rtc/class.c2
-rw-r--r--drivers/spi/spi.c2
-rw-r--r--drivers/usb/core/usb.c5
-rw-r--r--drivers/usb/gadget/udc-core.c4
-rw-r--r--drivers/usb/musb/musb_dsps.c2
-rw-r--r--drivers/video/backlight.c2
-rw-r--r--drivers/video/fb.c2
-rw-r--r--drivers/w1/w1.c4
-rw-r--r--drivers/watchdog/wd_core.c2
-rw-r--r--fs/fs.c2
-rw-r--r--include/driver.h25
-rw-r--r--include/linux/ethtool.h3
-rw-r--r--include/linux/phy.h9
-rw-r--r--include/linux/string.h12
-rw-r--r--include/of.h6
-rw-r--r--lib/libgen.c16
-rw-r--r--net/eth.c2
69 files changed, 2655 insertions, 155 deletions
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 5cf828ea36..2f13e2b98d 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -61,7 +61,7 @@
#define CR_TE (1 << 30) /* Thumb exception enable */
#ifndef __ASSEMBLY__
-#if __LINUX_ARM_ARCH__ >= 7
+#if __LINUX_ARM_ARCH__ > 7
static inline unsigned int current_el(void)
{
unsigned int el;
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index b2b250f3eb..edfc851138 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -84,58 +84,68 @@ comment "Freescale i.MX System-on-Chip"
config ARCH_IMX1
bool
select CPU_ARM920T
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V1
config ARCH_IMX21
bool
select CPU_ARM926T
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V1
config ARCH_IMX25
bool
select CPU_ARM926T
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V3
config ARCH_IMX27
bool
select CPU_ARM926T
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V1
config ARCH_IMX31
select CPU_V6
bool
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V2
config ARCH_IMX35
bool
select CPU_V6
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V3
config ARCH_IMX50
bool
select CPU_V7
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V3
config ARCH_IMX51
bool
select CPU_V7
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V3
config ARCH_IMX53
bool
select CPU_V7
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
select PINCTRL_IMX_IOMUX_V3
config ARCH_IMX6
bool
select ARCH_HAS_L2X0
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
select CPU_V7
select PINCTRL_IMX_IOMUX_V3
select OFTREE
@@ -163,6 +173,7 @@ config ARCH_IMX7
select OFTREE
select COMMON_CLK_OF_PROVIDER
select ARCH_HAS_FEC_IMX
+ select ARCH_HAS_IMX_GPT
config ARCH_IMX8MQ
bool
@@ -184,6 +195,7 @@ config ARCH_VF610
select COMMON_CLK_OF_PROVIDER
select NVMEM
select IMX_OCOTP # Needed for clock adjustement
+ select CLOCKSOURCE_ARM_GLOBAL_TIMER
config IMX_MULTI_BOARDS
bool "Allow multiple boards to be selected"
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 5a01dd57e8..97c54406e6 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -1,4 +1,3 @@
-obj-y += clocksource.o
obj-$(CONFIG_ARCH_IMX1) += imx1.o
obj-$(CONFIG_ARCH_IMX25) += imx25.o
obj-$(CONFIG_ARCH_IMX21) += imx21.o
diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c
index d4794cbac8..207e1879c3 100644
--- a/arch/arm/mach-imx/iim.c
+++ b/arch/arm/mach-imx/iim.c
@@ -474,7 +474,7 @@ static int imx_iim_probe(struct device_d *dev)
imx_iim = iim;
- strcpy(iim->dev.name, "iim");
+ dev_set_name(&iim->dev, "iim");
iim->dev.parent = dev;
iim->dev.id = DEVICE_ID_SINGLE;
ret = register_device(&iim->dev);
diff --git a/arch/arm/mach-imx/include/mach/devices-imx51.h b/arch/arm/mach-imx/include/mach/devices-imx51.h
index cccd8f4610..66fe643f82 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx51.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx51.h
@@ -81,7 +81,7 @@ static inline struct device_d *imx51_add_nand(struct imx_nand_platform_data *pda
dev->resource = xzalloc(sizeof(struct resource) * ARRAY_SIZE(res));
memcpy(dev->resource, res, sizeof(struct resource) * ARRAY_SIZE(res));
dev->num_resources = ARRAY_SIZE(res);
- strcpy(dev->name, "imx_nand");
+ dev_set_name(dev, "imx_nand");
dev->id = DEVICE_ID_DYNAMIC;
dev->platform_data = pdata;
diff --git a/arch/arm/mach-imx/include/mach/devices-imx53.h b/arch/arm/mach-imx/include/mach/devices-imx53.h
index 10caae8c93..27200a26d0 100644
--- a/arch/arm/mach-imx/include/mach/devices-imx53.h
+++ b/arch/arm/mach-imx/include/mach/devices-imx53.h
@@ -95,7 +95,7 @@ static inline struct device_d *imx53_add_nand(struct imx_nand_platform_data *pda
dev->resource = xzalloc(sizeof(struct resource) * ARRAY_SIZE(res));
memcpy(dev->resource, res, sizeof(struct resource) * ARRAY_SIZE(res));
dev->num_resources = ARRAY_SIZE(res);
- strcpy(dev->name, "imx_nand");
+ dev_set_name(dev, "imx_nand");
dev->id = DEVICE_ID_DYNAMIC;
dev->platform_data = pdata;
diff --git a/arch/arm/mach-mxs/include/mach/devices.h b/arch/arm/mach-mxs/include/mach/devices.h
index 5680d61c9e..b212aa783e 100644
--- a/arch/arm/mach-mxs/include/mach/devices.h
+++ b/arch/arm/mach-mxs/include/mach/devices.h
@@ -26,7 +26,7 @@ static inline struct device_d *mxs_add_nand(unsigned long gpmi_base, unsigned lo
dev->resource = xzalloc(sizeof(struct resource) * ARRAY_SIZE(res));
memcpy(dev->resource, res, sizeof(struct resource) * ARRAY_SIZE(res));
dev->num_resources = ARRAY_SIZE(res);
- strcpy(dev->name, "mxs_nand");
+ dev_set_name(dev, "mxs_nand");
dev->id = DEVICE_ID_DYNAMIC;
platform_device_register(dev);
diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c
index b41fde9919..01db731166 100644
--- a/arch/arm/mach-mxs/ocotp.c
+++ b/arch/arm/mach-mxs/ocotp.c
@@ -197,7 +197,7 @@ static int mxs_ocotp_probe(struct device_d *dev)
priv->cdev.size = cpu_is_mx23() ? 128 : 160;
priv->cdev.name = DRIVERNAME;
- strcpy(priv->dev.name, "ocotp");
+ dev_set_name(&priv->dev, "ocotp");
priv->dev.parent = dev;
err = register_device(&priv->dev);
if (err)
diff --git a/arch/sandbox/board/console.c b/arch/sandbox/board/console.c
index cf1781d156..006bbd1a6e 100644
--- a/arch/sandbox/board/console.c
+++ b/arch/sandbox/board/console.c
@@ -32,7 +32,7 @@ int barebox_register_console(int stdinfd, int stdoutfd)
data = (struct linux_console_data *)(dev + 1);
dev->platform_data = data;
- strcpy(dev->name, "console");
+ dev_set_name(dev, "console");
dev->id = DEVICE_ID_DYNAMIC;
data->stdoutfd = stdoutfd;
diff --git a/common/console.c b/common/console.c
index 40c26b66d9..47ccf2e54d 100644
--- a/common/console.c
+++ b/common/console.c
@@ -314,10 +314,10 @@ int console_register(struct console_device *newcdev)
if (newcdev->devname) {
dev->id = newcdev->devid;
- strcpy(dev->name, newcdev->devname);
+ dev_set_name(dev, newcdev->devname);
} else {
dev->id = DEVICE_ID_DYNAMIC;
- strcpy(dev->name, "cs");
+ dev_set_name(dev, "cs");
}
if (newcdev->dev)
diff --git a/common/state/state.c b/common/state/state.c
index 089d8f50d5..1597197ca2 100644
--- a/common/state/state.c
+++ b/common/state/state.c
@@ -179,7 +179,7 @@ static struct state *state_new(const char *name)
int ret;
state = xzalloc(sizeof(*state));
- safe_strncpy(state->dev.name, name, MAX_DRIVER_NAME);
+ dev_set_name(&state->dev, name);
state->name = state->dev.name;
state->dev.id = DEVICE_ID_SINGLE;
INIT_LIST_HEAD(&state->variables);
diff --git a/drivers/aiodev/core.c b/drivers/aiodev/core.c
index 79f935d710..b5d06da932 100644
--- a/drivers/aiodev/core.c
+++ b/drivers/aiodev/core.c
@@ -106,8 +106,6 @@ int aiodevice_register(struct aiodevice *aiodev)
aiodev->dev.id = DEVICE_ID_SINGLE;
aiodev->name = of_alias_get(aiodev->hwdev->device_node);
- if (!aiodev->name)
- aiodev->name = aiodev->hwdev->device_node->name;
}
if (!aiodev->name) {
@@ -115,7 +113,7 @@ int aiodevice_register(struct aiodevice *aiodev)
aiodev->dev.id = DEVICE_ID_DYNAMIC;
}
- strcpy(aiodev->dev.name, aiodev->name);
+ dev_set_name(&aiodev->dev, aiodev->name);
aiodev->dev.parent = aiodev->hwdev;
diff --git a/drivers/aiodev/imx_thermal.c b/drivers/aiodev/imx_thermal.c
index c020a1091d..9e50708355 100644
--- a/drivers/aiodev/imx_thermal.c
+++ b/drivers/aiodev/imx_thermal.c
@@ -177,6 +177,7 @@ static int imx_thermal_probe(struct device_d *dev)
imx_thermal->aiodev.num_channels = 1;
imx_thermal->aiodev.hwdev = dev;
+ imx_thermal->aiodev.name = "thermal-sensor";
imx_thermal->aiodev.channels =
xmalloc(imx_thermal->aiodev.num_channels *
sizeof(imx_thermal->aiodev.channels[0]));
diff --git a/drivers/aiodev/qoriq_thermal.c b/drivers/aiodev/qoriq_thermal.c
index d29da02a68..7556fef025 100644
--- a/drivers/aiodev/qoriq_thermal.c
+++ b/drivers/aiodev/qoriq_thermal.c
@@ -232,6 +232,7 @@ static int qoriq_tmu_probe(struct device_d *dev)
data->aiodev.num_channels = 1;
data->aiodev.hwdev = dev;
+ data->aiodev.name = "thermal-sensor";
data->aiodev.channels = xmalloc(data->aiodev.num_channels *
sizeof(data->aiodev.channels[0]));
data->aiodev.channels[0] = &data->aiochan;
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index ae5df13c96..a8cd16835d 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -200,7 +200,7 @@ struct amba_device *amba_device_alloc(const char *name, int id, resource_size_t
dev = xzalloc(sizeof(*dev));
- strcpy(dev->dev.name, name);
+ dev_set_name(&dev->dev, name);
dev->dev.id = id;
dev->res.start = base;
dev->res.end = base + size - 1;
diff --git a/drivers/ata/disk_ata_drive.c b/drivers/ata/disk_ata_drive.c
index 5ebddbdec8..11f7151e51 100644
--- a/drivers/ata/disk_ata_drive.c
+++ b/drivers/ata/disk_ata_drive.c
@@ -325,10 +325,10 @@ int ata_port_register(struct ata_port *port)
int ret;
if (port->devname) {
- strcpy(port->class_dev.name, port->devname);
+ dev_set_name(&port->class_dev, port->devname);
port->class_dev.id = DEVICE_ID_SINGLE;
} else {
- strcpy(port->class_dev.name, "ata");
+ dev_set_name(&port->class_dev, "ata");
port->class_dev.id = DEVICE_ID_DYNAMIC;
}
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index b889a48662..1038d20a12 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -32,7 +32,7 @@ int bus_register(struct bus_type *bus)
return -EEXIST;
bus->dev = xzalloc(sizeof(*bus->dev));
- strcpy(bus->dev->name, bus->name);
+ dev_set_name(bus->dev, bus->name);
bus->dev->id = DEVICE_ID_SINGLE;
ret = register_device(bus->dev);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 3b39c28494..4acc4cfa1e 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -183,6 +183,11 @@ int register_device(struct device_d *new_device)
}
}
+ if (new_device->id != DEVICE_ID_SINGLE)
+ new_device->unique_name = basprintf(FORMAT_DRIVER_NAME_ID,
+ new_device->name,
+ new_device->id);
+
debug ("register_device: %s\n", dev_name(new_device));
list_add_tail(&new_device->list, &device_list);
@@ -443,17 +448,39 @@ int dummy_probe(struct device_d *dev)
}
EXPORT_SYMBOL(dummy_probe);
-const char *dev_id(const struct device_d *dev)
+/**
+ * dev_set_name - set a device name
+ * @dev: device
+ * @fmt: format string for the device's name
+ *
+ * NOTE: This function expects dev->name to be free()-able, so extra
+ * precautions needs to be taken when mixing its usage with manual
+ * assignement of device_d.name.
+ */
+int dev_set_name(struct device_d *dev, const char *fmt, ...)
{
- static char buf[MAX_DRIVER_NAME + 16];
-
- if (dev->id != DEVICE_ID_SINGLE)
- snprintf(buf, sizeof(buf), FORMAT_DRIVER_NAME_ID, dev->name, dev->id);
- else
- snprintf(buf, sizeof(buf), "%s", dev->name);
-
- return buf;
+ va_list vargs;
+ int err;
+ /*
+ * Save old pointer in case we are overriding already set name
+ */
+ char *oldname = dev->name;
+
+ va_start(vargs, fmt);
+ err = vasprintf(&dev->name, fmt, vargs);
+ va_end(vargs);
+
+ /*
+ * Free old pointer, we do this after vasprintf call in case
+ * old device name was in one of vargs
+ */
+ free(oldname);
+
+ WARN_ON(err < 0);
+
+ return err;
}
+EXPORT_SYMBOL_GPL(dev_set_name);
static void devices_shutdown(void)
{
diff --git a/drivers/base/resource.c b/drivers/base/resource.c
index 6c2d7fed46..cb7105bf8d 100644
--- a/drivers/base/resource.c
+++ b/drivers/base/resource.c
@@ -27,7 +27,7 @@ struct device_d *device_alloc(const char *devname, int id)
struct device_d *dev;
dev = xzalloc(sizeof(*dev));
- strcpy(dev->name, devname);
+ dev_set_name(dev, devname);
dev->id = id;
return dev;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 3d63f7ff16..3caf72503a 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -1,3 +1,6 @@
+config ARCH_HAS_IMX_GPT
+ bool
+
config AMBA_SP804
bool
depends on ARM_AMBA
@@ -70,3 +73,10 @@ config CLOCKSOURCE_ARMV8_TIMER
bool
default y
depends on ARM && CPU_64v8
+
+config CLOCKSOURCE_ARM_GLOBAL_TIMER
+ bool
+ depends on ARM && CPU_V7
+config CLOCKSOURCE_IMX_GPT
+ def_bool y
+ depends on ARCH_HAS_IMX_GPT
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index ea33fff502..ce4d74137a 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -12,3 +12,5 @@ obj-$(CONFIG_CLOCKSOURCE_UEMD) += uemd.o
obj-$(CONFIG_CLOCKSOURCE_ROCKCHIP)+= rk_timer.o
obj-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += timer-atmel-pit.o
obj-$(CONFIG_CLOCKSOURCE_ARMV8_TIMER) += armv8-timer.o
+obj-$(CONFIG_CLOCKSOURCE_ARM_GLOBAL_TIMER) += arm_global_timer.o
+obj-$(CONFIG_CLOCKSOURCE_IMX_GPT) += timer-imx-gpt.o
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
new file mode 100644
index 0000000000..44e3a3c762
--- /dev/null
+++ b/drivers/clocksource/arm_global_timer.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Clocksource driver for generic Cortex A9 timer block
+ *
+ * Copyright (C) 2018 Zodiac Inflight Innovations
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * based on corresponding driver from Linux kernel with the following
+ * copyright:
+ *
+ * drivers/clocksource/arm_global_timer.c
+ *
+ * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
+ */
+#include <common.h>
+#include <init.h>
+#include <clock.h>
+#include <linux/clk.h>
+#include <io.h>
+#include <asm/system.h>
+
+#define GT_COUNTER0 0x00
+#define GT_COUNTER1 0x04
+
+#define GT_CONTROL 0x08
+#define GT_CONTROL_TIMER_ENABLE BIT(0) /* this bit is NOT banked */
+
+static void __iomem *gt_base;
+
+/*
+ * To get the value from the Global Timer Counter register proceed as follows:
+ * 1. Read the upper 32-bit timer counter register
+ * 2. Read the lower 32-bit timer counter register
+ * 3. Read the upper 32-bit timer counter register again. If the value is
+ * different to the 32-bit upper value read previously, go back to step 2.
+ * Otherwise the 64-bit timer counter value is correct.
+ */
+static uint64_t arm_global_clocksource_read(void)
+{
+ uint64_t counter;
+ uint32_t lower;
+ uint32_t upper, old_upper;
+
+ upper = readl(gt_base + GT_COUNTER1);
+ do {
+ old_upper = upper;
+ lower = readl(gt_base + GT_COUNTER0);
+ upper = readl(gt_base + GT_COUNTER1);
+ } while (upper != old_upper);
+
+ counter = upper;
+ counter <<= 32;
+ counter |= lower;
+ return counter;
+}
+
+static struct clocksource cs = {
+ .read = arm_global_clocksource_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .shift = 0,
+};
+
+static int arm_global_timer_probe(struct device_d *dev)
+{
+ struct resource *iores;
+ struct clk *clk;
+ int ret;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev, "clock not found: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_enable(clk);
+ if (ret) {
+ dev_err(dev, "clock failed to enable: %d\n", ret);
+ return ret;
+ }
+
+ gt_base = IOMEM(iores->start);
+
+ cs.mult = clocksource_hz2mult(clk_get_rate(clk), cs.shift);
+
+ writel(0, gt_base + GT_CONTROL);
+ writel(0, gt_base + GT_COUNTER0);
+ writel(0, gt_base + GT_COUNTER1);
+ /* enables timer on all the cores */
+ writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+
+ return init_clock(&cs);
+}
+
+static struct of_device_id arm_global_timer_dt_ids[] = {
+ { .compatible = "arm,cortex-a9-global-timer", },
+ { }
+};
+
+static struct driver_d arm_global_timer_driver = {
+ .name = "arm-global-timer",
+ .probe = arm_global_timer_probe,
+ .of_compatible = DRV_OF_COMPAT(arm_global_timer_dt_ids),
+};
+postcore_platform_driver(arm_global_timer_driver);
+
diff --git a/arch/arm/mach-imx/clocksource.c b/drivers/clocksource/timer-imx-gpt.c
index 4d6c6c2b0b..4d6c6c2b0b 100644
--- a/arch/arm/mach-imx/clocksource.c
+++ b/drivers/clocksource/timer-imx-gpt.c
diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c
index 3a27323a00..b7dea7c822 100644
--- a/drivers/efi/efi-device.c
+++ b/drivers/efi/efi-device.c
@@ -185,7 +185,7 @@ static struct efi_device *efi_add_device(efi_handle_t *handle, efi_guid_t **guid
efidev->dev.info = efi_devinfo;
efidev->devpath = devpath;
- sprintf(efidev->dev.name, "handle-%p", handle);
+ dev_set_name(&efidev->dev, "handle-%p", handle);
efidev->parent_handle = efi_find_parent(efidev->handle);
diff --git a/drivers/firmware/socfpga.c b/drivers/firmware/socfpga.c
index c1eae98acc..6d11da32a5 100644
--- a/drivers/firmware/socfpga.c
+++ b/drivers/firmware/socfpga.c
@@ -438,7 +438,7 @@ static int fpgamgr_probe(struct device_d *dev)
dev_dbg(dev, "Registering FPGA firmware programmer\n");
mgr->dev.id = DEVICE_ID_SINGLE;
- strcpy(mgr->dev.name, "fpga");
+ dev_set_name(&mgr->dev, "fpga");
mgr->dev.parent = dev;
ret = register_device(&mgr->dev);
if (ret)
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index 608f8289bf..25e0fe7add 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -389,7 +389,7 @@ static struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
int status;
client = xzalloc(sizeof *client);
- strcpy(client->dev.name, chip->type);
+ dev_set_name(&client->dev, chip->type);
client->dev.type_data = client;
client->dev.platform_data = chip->platform_data;
client->dev.id = DEVICE_ID_DYNAMIC;
@@ -588,7 +588,7 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
}
adapter->dev.id = adapter->nr;
- strcpy(adapter->dev.name, "i2c");
+ dev_set_name(&adapter->dev, "i2c");
ret = register_device(&adapter->dev);
if (ret)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index c6b4e02cbc..c8d1d5e164 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1802,10 +1802,10 @@ int mci_register(struct mci_host *host)
mci->host = host;
if (host->devname) {
- strcpy(mci->dev.name, host->devname);
+ dev_set_name(&mci->dev, host->devname);
mci->dev.id = DEVICE_ID_SINGLE;
} else {
- strcpy(mci->dev.name, "mci");
+ dev_set_name(&mci->dev, "mci");
mci->dev.id = DEVICE_ID_DYNAMIC;
}
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 15fe9ce798..56e85b3d8f 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -607,7 +607,7 @@ int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id)
if (!devname)
devname = "mtd";
- strcpy(mtd->class_dev.name, devname);
+ dev_set_name(&mtd->class_dev, devname);
mtd->class_dev.id = device_id;
if (mtd->parent)
mtd->class_dev.parent = mtd->parent;
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index 6269668187..ed5377bd4b 100644
--- a/drivers/mtd/spi-nor/cadence-quadspi.c
+++ b/drivers/mtd/spi-nor/cadence-quadspi.c
@@ -1051,7 +1051,7 @@ static int cqspi_setup_flash(struct device_d *dev,
if (np) {
nor->dev = xzalloc(sizeof(*nor->dev));
- strcpy(nor->dev->name, np->name);
+ dev_set_name(nor->dev, np->name);
nor->dev->device_node = np;
nor->dev->id = DEVICE_ID_SINGLE;
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 536077ebf3..493c778c3f 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -157,7 +157,7 @@ static int uif_init(struct ubi_device *ubi, int *ref)
*ref = 0;
sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
- sprintf(ubi->dev.name, "%s.ubi", ubi->mtd->cdev.name);
+ dev_set_name(&ubi->dev, "%s.ubi", ubi->mtd->cdev.name);
ubi->dev.id = DEVICE_ID_SINGLE;
ubi->dev.parent = &ubi->mtd->class_dev;
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 6177048214..99da79171b 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -145,7 +145,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
vol->last_eb_bytes = vol->usable_leb_size;
}
- sprintf(vol->dev.name, "%s.%s", dev_name(&ubi->dev), vol->name);
+ dev_set_name(&vol->dev, "%s.%s", dev_name(&ubi->dev), vol->name);
vol->dev.id = DEVICE_ID_SINGLE;
vol->dev.parent = &ubi->dev;
err = register_device(&vol->dev);
@@ -443,7 +443,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
dbg_gen("add volume");
- sprintf(vol->dev.name, "%s.%s", dev_name(&ubi->dev), vol->name);
+ dev_set_name(&vol->dev, "%s.%s", dev_name(&ubi->dev), vol->name);
vol->dev.id = DEVICE_ID_SINGLE;
vol->dev.parent = &ubi->dev;
err = register_device(&vol->dev);
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index 3d3939cfae..c6fc21dc54 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -916,7 +916,7 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num,
if (ret)
goto err_out;
- sprintf(dev->name, "cpsw-slave");
+ dev_set_name(dev, "cpsw-slave");
dev->id = slave->slave_num;
dev->parent = priv->dev;
ret = register_device(dev);
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index dda022e054..180b32ede8 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -1529,7 +1529,7 @@ int e1000_register_invm(struct e1000_hw *hw)
if (ret < 0)
return ret;
- strcpy(hw->invm.dev.name, "invm");
+ dev_set_name(&hw->invm.dev, "invm");
hw->invm.dev.id = hw->dev->id;
hw->invm.dev.parent = hw->dev;
ret = register_device(&hw->invm.dev);
diff --git a/drivers/net/orion-gbe.c b/drivers/net/orion-gbe.c
index e6bd757689..431ec5c31f 100644
--- a/drivers/net/orion-gbe.c
+++ b/drivers/net/orion-gbe.c
@@ -462,7 +462,7 @@ static int port_probe(struct device_d *parent, struct port_priv *port)
reg |= RGMII_ENABLE;
writel(reg, port->regs + PORT_SC1);
- snprintf(dev->name, MAX_DRIVER_NAME, "%08x.ethernet-port", (u32)gbe->regs);
+ dev_set_name(dev, "%08x.ethernet-port", (u32)gbe->regs);
dev->id = port->portno;
dev->parent = parent;
dev->device_node = port->np;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 79fb917ee7..3b1a6ea7e3 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -48,6 +48,12 @@ config SMSC_PHY
---help---
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
+config NET_DSA_MV88E6XXX
+ tristate "Marvell 88E6xxx Ethernet switch fabric support"
+ help
+ This driver adds support for most of the Marvell 88E6xxx models of
+ Ethernet switch chips, except 88E6060.
+
comment "MII bus device drivers"
config MDIO_MVEBU
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 4424054d91..e4d9ec65a3 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
+obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx/
obj-$(CONFIG_MDIO_MVEBU) += mdio-mvebu.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 7d53bcc3da..cda05afae7 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -26,6 +26,7 @@
#include <errno.h>
#include <linux/phy.h>
#include <linux/err.h>
+#include <of_device.h>
#define DEFAULT_GPIO_RESET_ASSERT 1000 /* us */
#define DEFAULT_GPIO_RESET_DEASSERT 1000 /* us */
@@ -179,8 +180,19 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
/* Loop over the child nodes and register a phy_device for each one */
for_each_available_child_of_node(np, child) {
- if (!of_mdiobus_child_is_phy(child))
+ if (!of_mdiobus_child_is_phy(child)) {
+ if (of_get_property(child, "compatible", NULL)) {
+ if (!of_platform_device_create(child,
+ &mdio->dev)) {
+ dev_err(&mdio->dev,
+ "Failed to create device "
+ "for %s\n",
+ child->full_name);
+ }
+ }
+
continue;
+ }
ret = of_property_read_u32(child, "reg", &addr);
if (ret) {
@@ -222,7 +234,7 @@ int mdiobus_register(struct mii_bus *bus)
bus->dev.priv = bus;
bus->dev.id = DEVICE_ID_DYNAMIC;
- strcpy(bus->dev.name, "miibus");
+ dev_set_name(&bus->dev, "miibus");
bus->dev.parent = bus->parent;
bus->dev.detect = mdiobus_detect;
@@ -335,16 +347,19 @@ EXPORT_SYMBOL(of_mdio_find_bus);
* @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.
+ * Description: Given a PHY device, and a PHY driver, return 0 if
+ * the driver supports the device. Otherwise, return 1.
*/
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));
+ if ((phydrv->phy_id & phydrv->phy_id_mask) ==
+ (phydev->phy_id & phydrv->phy_id_mask))
+ return 0;
+
+ return 1;
}
static ssize_t phydev_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
diff --git a/drivers/net/phy/mv88e6xxx/Makefile b/drivers/net/phy/mv88e6xxx/Makefile
new file mode 100644
index 0000000000..e09ea0aa47
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/Makefile
@@ -0,0 +1,5 @@
+obj-y += mv88e6xxx.o
+
+mv88e6xxx-objs := chip.o
+mv88e6xxx-objs += global2.o
+mv88e6xxx-objs += port.o
diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
new file mode 100644
index 0000000000..ac08b5ef54
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/chip.c
@@ -0,0 +1,913 @@
+#include <common.h>
+#include <init.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/bitfield.h>
+#include <linux/nvmem-provider.h>
+
+#include <gpio.h>
+#include <of_device.h>
+#include <of_gpio.h>
+
+#include "chip.h"
+#include "global2.h"
+#include "port.h"
+
+
+/* List of supported models */
+enum mv88e6xxx_model {
+ MV88E6085,
+ MV88E6095,
+ MV88E6097,
+ MV88E6123,
+ MV88E6131,
+ MV88E6141,
+ MV88E6161,
+ MV88E6165,
+ MV88E6171,
+ MV88E6172,
+ MV88E6175,
+ MV88E6176,
+ MV88E6185,
+ MV88E6190,
+ MV88E6190X,
+ MV88E6191,
+ MV88E6240,
+ MV88E6290,
+ MV88E6320,
+ MV88E6321,
+ MV88E6341,
+ MV88E6350,
+ MV88E6351,
+ MV88E6352,
+ MV88E6390,
+ MV88E6390X,
+};
+
+static const struct mv88e6xxx_ops mv88e6085_ops = {
+ /* MV88E6XXX_FAMILY_6097 */
+ /* FIXME: Was not ported due to lack of HW */
+ .phy_read = NULL,
+ .phy_write = NULL,
+};
+
+static const struct mv88e6xxx_ops mv88e6095_ops = {
+ /* MV88E6XXX_FAMILY_6095 */
+ /* FIXME: Was not ported due to lack of HW */
+ .phy_read = NULL,
+ .phy_write = NULL,
+};
+
+static const struct mv88e6xxx_ops mv88e6097_ops = {
+ /* MV88E6XXX_FAMILY_6097 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6123_ops = {
+ /* MV88E6XXX_FAMILY_6165 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6131_ops = {
+ /* MV88E6XXX_FAMILY_6185 */
+ /* FIXME: Was not ported due to lack of HW */
+ .phy_read = NULL,
+ .phy_write = NULL,
+};
+
+static const struct mv88e6xxx_ops mv88e6141_ops = {
+ /* MV88E6XXX_FAMILY_6341 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6161_ops = {
+ /* MV88E6XXX_FAMILY_6165 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6165_ops = {
+ /* MV88E6XXX_FAMILY_6165 */
+ /* FIXME: Was not ported due to lack of HW */
+ .phy_read = NULL,
+ .phy_write = NULL,
+};
+
+static const struct mv88e6xxx_ops mv88e6171_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6172_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6352_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6175_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6176_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6352_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6185_ops = {
+ /* MV88E6XXX_FAMILY_6185 */
+ /* FIXME: Was not ported due to lack of HW */
+ .phy_read = NULL,
+ .phy_write = NULL,
+};
+
+static const struct mv88e6xxx_ops mv88e6190_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6190x_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390x_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6191_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6240_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6352_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6290_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390_port_set_speed,
+ .port_set_cmode = mv88e6390x_port_set_cmode,
+};
+
+static const struct mv88e6xxx_ops mv88e6320_ops = {
+ /* MV88E6XXX_FAMILY_6320 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6321_ops = {
+ /* MV88E6XXX_FAMILY_6320 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6341_ops = {
+ /* MV88E6XXX_FAMILY_6341 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6350_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6351_ops = {
+ /* MV88E6XXX_FAMILY_6351 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6185_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6352_ops = {
+ /* MV88E6XXX_FAMILY_6352 */
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
+ .port_set_speed = mv88e6352_port_set_speed,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6390_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390_port_set_speed,
+ .port_set_cmode = mv88e6390x_port_set_cmode,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_ops mv88e6390x_ops = {
+ /* MV88E6XXX_FAMILY_6390 */
+ .get_eeprom = mv88e6xxx_g2_get_eeprom8,
+ .set_eeprom = mv88e6xxx_g2_set_eeprom8,
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
+ .port_set_link = mv88e6xxx_port_set_link,
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
+ .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
+ .port_set_speed = mv88e6390x_port_set_speed,
+ .port_set_cmode = mv88e6390x_port_set_cmode,
+ .port_link_state = mv88e6352_port_link_state,
+};
+
+static const struct mv88e6xxx_info mv88e6xxx_table[] = {
+ [MV88E6085] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
+ .family = MV88E6XXX_FAMILY_6097,
+ .name = "Marvell 88E6085",
+ .num_ports = 10,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6085_ops,
+ },
+
+ [MV88E6095] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6095,
+ .family = MV88E6XXX_FAMILY_6095,
+ .name = "Marvell 88E6095/88E6095F",
+ .num_ports = 11,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6095_ops,
+ },
+
+ [MV88E6097] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6097,
+ .family = MV88E6XXX_FAMILY_6097,
+ .name = "Marvell 88E6097/88E6097F",
+ .num_ports = 11,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6097_ops,
+ },
+
+ [MV88E6123] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6123,
+ .family = MV88E6XXX_FAMILY_6165,
+ .name = "Marvell 88E6123",
+ .num_ports = 3,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6123_ops,
+ },
+
+ [MV88E6131] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6131,
+ .family = MV88E6XXX_FAMILY_6185,
+ .name = "Marvell 88E6131",
+ .num_ports = 8,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6131_ops,
+ },
+
+ [MV88E6141] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6141,
+ .family = MV88E6XXX_FAMILY_6341,
+ .name = "Marvell 88E6341",
+ .num_ports = 6,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6141_ops,
+ },
+
+ [MV88E6161] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6161,
+ .family = MV88E6XXX_FAMILY_6165,
+ .name = "Marvell 88E6161",
+ .num_ports = 6,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6161_ops,
+ },
+
+ [MV88E6165] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6165,
+ .family = MV88E6XXX_FAMILY_6165,
+ .name = "Marvell 88E6165",
+ .num_ports = 6,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6165_ops,
+ },
+
+ [MV88E6171] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6171,
+ .family = MV88E6XXX_FAMILY_6351,
+ .name = "Marvell 88E6171",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6171_ops,
+ },
+
+ [MV88E6172] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6172,
+ .family = MV88E6XXX_FAMILY_6352,
+ .name = "Marvell 88E6172",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6172_ops,
+ },
+
+ [MV88E6175] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6175,
+ .family = MV88E6XXX_FAMILY_6351,
+ .name = "Marvell 88E6175",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6175_ops,
+ },
+
+ [MV88E6176] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6176,
+ .family = MV88E6XXX_FAMILY_6352,
+ .name = "Marvell 88E6176",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6176_ops,
+ },
+
+ [MV88E6185] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6185,
+ .family = MV88E6XXX_FAMILY_6185,
+ .name = "Marvell 88E6185",
+ .num_ports = 10,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6185_ops,
+ },
+
+ [MV88E6190] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6190",
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6190_ops,
+ },
+
+ [MV88E6190X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6190X,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6190X",
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6190x_ops,
+ },
+
+ [MV88E6191] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6191,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6191",
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6191_ops,
+ },
+
+ [MV88E6240] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6240,
+ .family = MV88E6XXX_FAMILY_6352,
+ .name = "Marvell 88E6240",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6240_ops,
+ },
+
+ [MV88E6290] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6290",
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6290_ops,
+ },
+
+ [MV88E6320] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6320,
+ .family = MV88E6XXX_FAMILY_6320,
+ .name = "Marvell 88E6320",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6320_ops,
+ },
+
+ [MV88E6321] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6321,
+ .family = MV88E6XXX_FAMILY_6320,
+ .name = "Marvell 88E6321",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6321_ops,
+ },
+
+ [MV88E6341] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6341,
+ .family = MV88E6XXX_FAMILY_6341,
+ .name = "Marvell 88E6341",
+ .num_ports = 6,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6341_ops,
+ },
+
+ [MV88E6350] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6350,
+ .family = MV88E6XXX_FAMILY_6351,
+ .name = "Marvell 88E6350",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6350_ops,
+ },
+
+ [MV88E6351] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6351,
+ .family = MV88E6XXX_FAMILY_6351,
+ .name = "Marvell 88E6351",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6351_ops,
+ },
+
+ [MV88E6352] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6352,
+ .family = MV88E6XXX_FAMILY_6352,
+ .name = "Marvell 88E6352",
+ .num_ports = 7,
+ .port_base_addr = 0x10,
+ .ops = &mv88e6352_ops,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6352_ops,
+ },
+
+ [MV88E6390] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6390",
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6390_ops,
+ },
+
+ [MV88E6390X] = {
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6390X,
+ .family = MV88E6XXX_FAMILY_6390,
+ .name = "Marvell 88E6390X",
+ .num_ports = 11, /* 10 + Z80 */
+ .port_base_addr = 0x0,
+ .global2_addr = 0x1c,
+ .ops = &mv88e6390x_ops,
+ },
+};
+
+int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
+{
+ int ret;
+ ret = mdiobus_write(chip->parent_miibus, addr, reg, val);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(chip->dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
+ addr, reg, val);
+
+ return 0;
+}
+
+int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
+{
+ int ret;
+
+ ret = mdiobus_read(chip->parent_miibus, addr, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret & 0xffff;
+
+ dev_dbg(chip->dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
+ addr, reg, *val);
+
+ return 0;
+}
+
+int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_read(chip, addr, reg, &val);
+ if (err)
+ return err;
+
+ if (!(val & mask))
+ return 0;
+
+ udelay(2000);
+ }
+
+ dev_err(chip->dev, "Timeout while waiting for switch\n");
+ return -ETIMEDOUT;
+}
+
+static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct mv88e6xxx_chip *chip = bus->priv;
+ u16 val;
+ int err;
+
+ if (!chip->info->ops->phy_read)
+ return -EOPNOTSUPP;
+
+ err = chip->info->ops->phy_read(chip, bus, phy, reg, &val);
+
+ if (reg == MII_PHYSID2) {
+ /* Some internal PHYS don't have a model number. Use
+ * the mv88e6390 family model number instead.
+ */
+ if (!(val & 0x3f0))
+ val |= MV88E6XXX_PORT_SWITCH_ID_PROD_6390 >> 4;
+ }
+
+ return err ?: val;
+}
+
+static int mv88e6xxx_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+ struct mv88e6xxx_chip *chip = bus->priv;
+ int err;
+
+ if (!chip->info->ops->phy_write)
+ return -EOPNOTSUPP;
+
+ err = chip->info->ops->phy_write(chip, bus, phy, reg, val);
+
+ return err;
+}
+
+static const struct mv88e6xxx_info *
+mv88e6xxx_lookup_info(unsigned int prod_num)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mv88e6xxx_table); ++i)
+ if (mv88e6xxx_table[i].prod_num == prod_num)
+ return &mv88e6xxx_table[i];
+
+ return NULL;
+}
+
+static int mv88e6xxx_detect(struct mv88e6xxx_chip *chip)
+{
+ const struct mv88e6xxx_info *info;
+ unsigned int prod_num, rev;
+ u16 id;
+ int err;
+
+ err = mv88e6xxx_port_read(chip, 0, MV88E6XXX_PORT_SWITCH_ID, &id);
+ if (err)
+ return err;
+
+ prod_num = id & MV88E6XXX_PORT_SWITCH_ID_PROD_MASK;
+ rev = id & MV88E6XXX_PORT_SWITCH_ID_REV_MASK;
+
+ info = mv88e6xxx_lookup_info(prod_num);
+ if (!info)
+ return -ENODEV;
+
+ /* Update the compatible info with the probed one */
+ chip->info = info;
+
+ dev_info(chip->dev, "switch 0x%x detected: %s, revision %u\n",
+ chip->info->prod_num, chip->info->name, rev);
+
+ return 0;
+}
+
+/*
+ * Linux driver has this delay at 20ms, but it doesn't seem to be
+ * enough in Barebox and trying to access switch registers immediately
+ * after this function will return all F's on some platforms
+ * tested. Increasing this to 50ms seem to resolve the issue.
+ */
+static void mv88e6xxx_hardware_reset_delay(void)
+{
+ udelay(50000);
+}
+
+static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
+{
+ /* If there is a GPIO connected to the reset pin, toggle it */
+ if (gpio_is_valid(chip->reset)) {
+ gpio_set_active(chip->reset, 1);
+ mv88e6xxx_hardware_reset_delay();
+ gpio_set_active(chip->reset, 0);
+ mv88e6xxx_hardware_reset_delay();
+ }
+}
+
+static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
+{
+ mv88e6xxx_hardware_reset(chip);
+ return 0;
+}
+
+static int mv88e6xxx_eeprom_read(struct device_d *dev, const int offset,
+ void *val, int bytes)
+{
+ struct mv88e6xxx_chip *chip = dev->parent->priv;
+ struct ethtool_eeprom eeprom = {
+ .offset = offset,
+ .len = bytes,
+ };
+
+ if (!chip->info->ops->get_eeprom)
+ return -ENOTSUPP;
+
+ return chip->info->ops->get_eeprom(chip, &eeprom, val);
+}
+
+static int mv88e6xxx_eeprom_write(struct device_d *dev, const int offset,
+ const void *val, int bytes)
+{
+ struct mv88e6xxx_chip *chip = dev->parent->priv;
+ struct ethtool_eeprom eeprom = {
+ .offset = offset,
+ .len = bytes,
+ };
+
+ if (!chip->info->ops->set_eeprom)
+ return -ENOTSUPP;
+
+ return chip->info->ops->set_eeprom(chip, &eeprom, (void *)val);
+}
+
+static const struct nvmem_bus mv88e6xxx_eeprom_nvmem_bus = {
+ .write = mv88e6xxx_eeprom_write,
+ .read = mv88e6xxx_eeprom_read,
+};
+
+static int mv88e6xxx_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node;
+ struct device_node *mdio_node;
+ struct mv88e6xxx_chip *chip;
+ enum of_gpio_flags of_flags;
+ u32 eeprom_len = 0;
+ int err;
+ u32 reg;
+
+ err = of_property_read_u32(np, "reg", &reg);
+ if (err) {
+ dev_err(dev, "Couldn't determine switch MIDO address\n");
+ return err;
+ }
+
+ if (reg) {
+ dev_err(dev, "Only single-chip address mode is supported\n");
+ return -ENOTSUPP;
+ }
+
+ chip = xzalloc(sizeof(struct mv88e6xxx_chip));
+ chip->dev = dev;
+ dev->priv = chip;
+ chip->info = of_device_get_match_data(dev);
+
+ of_property_read_u32(np, "eeprom-length", &eeprom_len);
+
+ chip->parent_miibus = of_mdio_find_bus(np->parent);
+ if (!chip->parent_miibus)
+ return -EPROBE_DEFER;
+
+ chip->reset = of_get_named_gpio_flags(np, "reset-gpios", 0, &of_flags);
+ if (gpio_is_valid(chip->reset)) {
+ unsigned long flags = GPIOF_OUT_INIT_INACTIVE;
+ char *name;
+
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ name = basprintf("%s reset", dev_name(dev));
+ err = gpio_request_one(chip->reset, flags, name);
+ if (err < 0)
+ return err;
+ /*
+ * We assume that reset line was previously held low
+ * and give the switch time to initialize before
+ * trying to read its registers
+ */
+ mv88e6xxx_hardware_reset_delay();
+ }
+
+ err = mv88e6xxx_detect(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_switch_reset(chip);
+ if (err)
+ return err;
+
+ if (eeprom_len) {
+ struct nvmem_config config = {
+ .name = basprintf("%s-eeprom", dev_name(dev)),
+ .dev = dev,
+ .word_size = 1,
+ .stride = 1,
+ .size = eeprom_len,
+ .read_only = false,
+ .bus = &mv88e6xxx_eeprom_nvmem_bus,
+ };
+
+ if (IS_ERR(nvmem_register(&config)))
+ dev_err(dev, "Failed to register EEPROM\n");
+ }
+
+ /*
+ * In single-chip address mode addresses 0x10 -
+ * port_base_address are reserved to access various switch
+ * registers and do not correspond to any PHYs, so we mask
+ * them to pervent from being exposed.
+ */
+ chip->parent_miibus->phy_mask |= GENMASK(0x1f,
+ chip->info->port_base_addr);
+ /*
+ * Mask all of the devices on child MDIO bus. Call to
+ * mv88e6xxx_port_probe() will unmask port that can be probed
+ * using standard methods
+ */
+ chip->miibus.phy_mask |= GENMASK(0x1f, 0x00);
+
+ chip->miibus.read = mv88e6xxx_mdio_read;
+ chip->miibus.write = mv88e6xxx_mdio_write;
+
+ chip->miibus.priv = chip;
+ chip->miibus.parent = dev;
+
+ mdio_node = of_get_child_by_name(np, "mdio");
+ if (mdio_node)
+ chip->miibus.dev.device_node = mdio_node;
+
+ err = mv88e6xxx_port_probe(chip);
+ if (err)
+ return err;
+
+ return mdiobus_register(&chip->miibus);
+}
+
+static const struct of_device_id mv88e6xxx_of_match[] = {
+ {
+ .compatible = "marvell,mv88e6085",
+ .data = &mv88e6xxx_table[MV88E6085],
+ },
+ {
+ .compatible = "marvell,mv88e6190",
+ .data = &mv88e6xxx_table[MV88E6190],
+ },
+ {},
+};
+
+static struct driver_d mv88e6xxx_driver = {
+ .name = "mv88e6085",
+ .probe = mv88e6xxx_probe,
+ .of_compatible = mv88e6xxx_of_match,
+};
+device_platform_driver(mv88e6xxx_driver);
diff --git a/drivers/net/phy/mv88e6xxx/chip.h b/drivers/net/phy/mv88e6xxx/chip.h
new file mode 100644
index 0000000000..7548358de0
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/chip.h
@@ -0,0 +1,142 @@
+#ifndef _MV88E6XXX_CHIP_H
+#define _MV88E6XXX_CHIP_H
+
+#include <common.h>
+#include <init.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+/* sub-devices MDIO addresses */
+#define MV88E6XXX_SWITCH_GLOBAL_REGS_1 0x1b
+#define MV88E6XXX_SWITCH_GLOBAL_REGS_2 0x1c
+
+enum mv88e6xxx_family {
+ MV88E6XXX_FAMILY_NONE,
+ MV88E6XXX_FAMILY_6065, /* 6031 6035 6061 6065 */
+ MV88E6XXX_FAMILY_6095, /* 6092 6095 */
+ MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */
+ MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */
+ MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */
+ MV88E6XXX_FAMILY_6320, /* 6320 6321 */
+ MV88E6XXX_FAMILY_6341, /* 6141 6341 */
+ MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
+ MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */
+ MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */
+};
+
+struct mv88e6xxx_ops;
+
+#define DSA_MAX_PORTS 12
+
+struct mv88e6xxx_info {
+ enum mv88e6xxx_family family;
+ u16 prod_num;
+ const char *name;
+ unsigned int num_ports;
+ unsigned int port_base_addr;
+ unsigned int global2_addr;
+
+ const struct mv88e6xxx_ops *ops;
+};
+
+struct mv88e6xxx_port {
+ u8 cmode;
+};
+
+struct mv88e6xxx_chip {
+ const struct mv88e6xxx_info *info;
+ struct mii_bus *parent_miibus;
+ struct mii_bus miibus;
+ struct device_d *dev;
+ int reset;
+
+ /* Array of port structures. */
+ struct mv88e6xxx_port ports[DSA_MAX_PORTS];
+};
+
+struct ethtool_eeprom {
+ __u32 offset;
+ __u32 len;
+};
+
+struct phylink_link_state {
+ phy_interface_t interface;
+ int speed;
+ int duplex;
+ int pause;
+ unsigned int link:1;
+ unsigned int an_enabled:1;
+ unsigned int an_complete:1;
+};
+
+struct mv88e6xxx_ops {
+ int (*phy_read)(struct mv88e6xxx_chip *chip,
+ struct mii_bus *bus,
+ int addr, int reg, u16 *val);
+ int (*phy_write)(struct mv88e6xxx_chip *chip,
+ struct mii_bus *bus,
+ int addr, int reg, u16 val);
+
+ int (*get_eeprom)(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data);
+ int (*set_eeprom)(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data);
+
+ /* RGMII Receive/Transmit Timing Control
+ * Add delay on PHY_INTERFACE_MODE_RGMII_*ID, no delay otherwise.
+ */
+ int (*port_set_rgmii_delay)(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
+
+#define LINK_FORCED_DOWN 0
+#define LINK_FORCED_UP 1
+#define LINK_UNFORCED -2
+
+ /* Port's MAC link state
+ * Use LINK_FORCED_UP or LINK_FORCED_DOWN to force link up or down,
+ * or LINK_UNFORCED for normal link detection.
+ */
+ int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link);
+
+#define DUPLEX_UNFORCED -2
+
+ /* Port's MAC duplex mode
+ *
+ * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex,
+ * or DUPLEX_UNFORCED for normal duplex detection.
+ */
+ int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup);
+
+#define PAUSE_ON 1
+#define PAUSE_OFF 0
+
+ /* Enable/disable sending Pause */
+ int (*port_set_pause)(struct mv88e6xxx_chip *chip, int port,
+ int pause);
+
+#define SPEED_MAX INT_MAX
+#define SPEED_UNFORCED -2
+
+ /* Port's MAC speed (in Mbps)
+ *
+ * Depending on the chip, 10, 100, 200, 1000, 2500, 10000 are valid.
+ * Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value.
+ */
+ int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed);
+
+ /* CMODE control what PHY mode the MAC will use, eg. SGMII, RGMII, etc.
+ * Some chips allow this to be configured on specific ports.
+ */
+ int (*port_set_cmode)(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
+
+ /* Return the port link state, as required by phylink */
+ int (*port_link_state)(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state);
+};
+
+int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
+int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val);
+int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask);
+
+#endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/phy/mv88e6xxx/global2.c b/drivers/net/phy/mv88e6xxx/global2.c
new file mode 100644
index 0000000000..970a7291e7
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/global2.c
@@ -0,0 +1,389 @@
+#include <linux/ethtool.h>
+#include <linux/bitfield.h>
+
+#include "global2.h"
+
+int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
+{
+ return mv88e6xxx_read(chip, chip->info->global2_addr, reg, val);
+}
+
+int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
+{
+ return mv88e6xxx_write(chip, chip->info->global2_addr, reg, val);
+}
+
+int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
+{
+ return mv88e6xxx_wait(chip, chip->info->global2_addr, reg, mask);
+}
+
+/* Offset 0x14: EEPROM Command
+ * Offset 0x15: EEPROM Data (for 16-bit data access)
+ * Offset 0x15: EEPROM Addr (for 8-bit data access)
+ */
+
+static int mv88e6xxx_g2_eeprom_wait(struct mv88e6xxx_chip *chip)
+{
+ return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_EEPROM_CMD,
+ MV88E6XXX_G2_EEPROM_CMD_BUSY |
+ MV88E6XXX_G2_EEPROM_CMD_RUNNING);
+}
+
+static int mv88e6xxx_g2_eeprom_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
+{
+ int err;
+
+ err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_EEPROM_CMD,
+ MV88E6XXX_G2_EEPROM_CMD_BUSY | cmd);
+ if (err)
+ return err;
+
+ return mv88e6xxx_g2_eeprom_wait(chip);
+}
+
+static int mv88e6xxx_g2_eeprom_read8(struct mv88e6xxx_chip *chip,
+ u16 addr, u8 *data)
+{
+ u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ;
+ int err;
+
+ err = mv88e6xxx_g2_eeprom_wait(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &cmd);
+ if (err)
+ return err;
+
+ *data = cmd & 0xff;
+
+ return 0;
+}
+
+static int mv88e6xxx_g2_eeprom_write8(struct mv88e6xxx_chip *chip,
+ u16 addr, u8 data)
+{
+ u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE |
+ MV88E6XXX_G2_EEPROM_CMD_WRITE_EN;
+ int err;
+
+ err = mv88e6xxx_g2_eeprom_wait(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_write(chip, MV88E6390_G2_EEPROM_ADDR, addr);
+ if (err)
+ return err;
+
+ return mv88e6xxx_g2_eeprom_cmd(chip, cmd | data);
+}
+
+static int mv88e6xxx_g2_eeprom_read16(struct mv88e6xxx_chip *chip,
+ u8 addr, u16 *data)
+{
+ u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_READ | addr;
+ int err;
+
+ err = mv88e6xxx_g2_eeprom_wait(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_eeprom_cmd(chip, cmd);
+ if (err)
+ return err;
+
+ return mv88e6xxx_g2_read(chip, MV88E6352_G2_EEPROM_DATA, data);
+}
+
+static int mv88e6xxx_g2_eeprom_write16(struct mv88e6xxx_chip *chip,
+ u8 addr, u16 data)
+{
+ u16 cmd = MV88E6XXX_G2_EEPROM_CMD_OP_WRITE | addr;
+ int err;
+
+ err = mv88e6xxx_g2_eeprom_wait(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_write(chip, MV88E6352_G2_EEPROM_DATA, data);
+ if (err)
+ return err;
+
+ return mv88e6xxx_g2_eeprom_cmd(chip, cmd);
+}
+
+int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ unsigned int offset = eeprom->offset;
+ unsigned int len = eeprom->len;
+ int err;
+
+ eeprom->len = 0;
+
+ while (len) {
+ err = mv88e6xxx_g2_eeprom_read8(chip, offset, data);
+ if (err)
+ return err;
+
+ eeprom->len++;
+ offset++;
+ data++;
+ len--;
+ }
+
+ return 0;
+}
+
+int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ unsigned int offset = eeprom->offset;
+ unsigned int len = eeprom->len;
+ int err;
+
+ eeprom->len = 0;
+
+ while (len) {
+ err = mv88e6xxx_g2_eeprom_write8(chip, offset, *data);
+ if (err)
+ return err;
+
+ eeprom->len++;
+ offset++;
+ data++;
+ len--;
+ }
+
+ return 0;
+}
+
+int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ unsigned int offset = eeprom->offset;
+ unsigned int len = eeprom->len;
+ u16 val;
+ int err;
+
+ eeprom->len = 0;
+
+ if (offset & 1) {
+ err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
+ if (err)
+ return err;
+
+ *data++ = (val >> 8) & 0xff;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ while (len >= 2) {
+ err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
+ if (err)
+ return err;
+
+ *data++ = val & 0xff;
+ *data++ = (val >> 8) & 0xff;
+
+ offset += 2;
+ len -= 2;
+ eeprom->len += 2;
+ }
+
+ if (len) {
+ err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
+ if (err)
+ return err;
+
+ *data++ = val & 0xff;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ return 0;
+}
+
+int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ unsigned int offset = eeprom->offset;
+ unsigned int len = eeprom->len;
+ u16 val;
+ int err;
+
+ /* Ensure the RO WriteEn bit is set */
+ err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_EEPROM_CMD, &val);
+ if (err)
+ return err;
+
+ if (!(val & MV88E6XXX_G2_EEPROM_CMD_WRITE_EN))
+ return -EROFS;
+
+ eeprom->len = 0;
+
+ if (offset & 1) {
+ err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
+ if (err)
+ return err;
+
+ val = (*data++ << 8) | (val & 0xff);
+
+ err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
+ if (err)
+ return err;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ while (len >= 2) {
+ val = *data++;
+ val |= *data++ << 8;
+
+ err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
+ if (err)
+ return err;
+
+ offset += 2;
+ len -= 2;
+ eeprom->len += 2;
+ }
+
+ if (len) {
+ err = mv88e6xxx_g2_eeprom_read16(chip, offset >> 1, &val);
+ if (err)
+ return err;
+
+ val = (val & 0xff00) | *data++;
+
+ err = mv88e6xxx_g2_eeprom_write16(chip, offset >> 1, val);
+ if (err)
+ return err;
+
+ offset++;
+ len--;
+ eeprom->len++;
+ }
+
+ return 0;
+}
+
+static int mv88e6xxx_g2_smi_phy_wait(struct mv88e6xxx_chip *chip)
+{
+ return mv88e6xxx_g2_wait(chip, MV88E6XXX_G2_SMI_PHY_CMD,
+ MV88E6XXX_G2_SMI_PHY_CMD_BUSY);
+}
+
+static int mv88e6xxx_g2_smi_phy_cmd(struct mv88e6xxx_chip *chip, u16 cmd)
+{
+ int err;
+
+ err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_CMD,
+ MV88E6XXX_G2_SMI_PHY_CMD_BUSY | cmd);
+ if (err)
+ return err;
+
+ return mv88e6xxx_g2_smi_phy_wait(chip);
+}
+
+static int mv88e6xxx_g2_smi_phy_access(struct mv88e6xxx_chip *chip,
+ bool external, bool c45, u16 op, int dev,
+ int reg)
+{
+ u16 cmd = op;
+
+ if (external)
+ cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL;
+ else
+ cmd |= MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL; /* empty mask */
+
+ if (c45)
+ cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_45; /* empty mask */
+ else
+ cmd |= MV88E6XXX_G2_SMI_PHY_CMD_MODE_22;
+
+ dev <<= __bf_shf(MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK);
+ cmd |= dev & MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK;
+ cmd |= reg & MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK;
+
+ return mv88e6xxx_g2_smi_phy_cmd(chip, cmd);
+}
+
+static int mv88e6xxx_g2_smi_phy_access_c22(struct mv88e6xxx_chip *chip,
+ bool external, u16 op, int dev,
+ int reg)
+{
+ return mv88e6xxx_g2_smi_phy_access(chip, external, false, op, dev, reg);
+}
+
+/* IEEE 802.3 Clause 22 Read Data Register */
+static int mv88e6xxx_g2_smi_phy_read_data_c22(struct mv88e6xxx_chip *chip,
+ bool external, int dev, int reg,
+ u16 *data)
+{
+ u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA;
+ int err;
+
+ err = mv88e6xxx_g2_smi_phy_wait(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
+ if (err)
+ return err;
+
+ return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
+}
+
+/* IEEE 802.3 Clause 22 Write Data Register */
+static int mv88e6xxx_g2_smi_phy_write_data_c22(struct mv88e6xxx_chip *chip,
+ bool external, int dev, int reg,
+ u16 data)
+{
+ u16 op = MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA;
+ int err;
+
+ err = mv88e6xxx_g2_smi_phy_wait(chip);
+ if (err)
+ return err;
+
+ err = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SMI_PHY_DATA, data);
+ if (err)
+ return err;
+
+ return mv88e6xxx_g2_smi_phy_access_c22(chip, external, op, dev, reg);
+}
+
+
+int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 *val)
+{
+ bool external = false;
+
+ return mv88e6xxx_g2_smi_phy_read_data_c22(chip, external, addr, reg,
+ val);
+}
+
+int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 val)
+{
+ bool external = false;
+
+ return mv88e6xxx_g2_smi_phy_write_data_c22(chip, external, addr, reg,
+ val);
+}
diff --git a/drivers/net/phy/mv88e6xxx/global2.h b/drivers/net/phy/mv88e6xxx/global2.h
new file mode 100644
index 0000000000..4e23b04232
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/global2.h
@@ -0,0 +1,70 @@
+#ifndef _MV88E6XXX_GLOBAL2_H
+#define _MV88E6XXX_GLOBAL2_H
+
+#include "chip.h"
+
+/* Offset 0x18: SMI PHY Command Register */
+#define MV88E6XXX_G2_SMI_PHY_CMD 0x18
+#define MV88E6XXX_G2_SMI_PHY_CMD_BUSY 0x8000
+#define MV88E6390_G2_SMI_PHY_CMD_FUNC_MASK 0x6000
+#define MV88E6390_G2_SMI_PHY_CMD_FUNC_INTERNAL 0x0000
+#define MV88E6390_G2_SMI_PHY_CMD_FUNC_EXTERNAL 0x2000
+#define MV88E6390_G2_SMI_PHY_CMD_FUNC_SETUP 0x4000
+#define MV88E6XXX_G2_SMI_PHY_CMD_MODE_MASK 0x1000
+#define MV88E6XXX_G2_SMI_PHY_CMD_MODE_45 0x0000
+#define MV88E6XXX_G2_SMI_PHY_CMD_MODE_22 0x1000
+#define MV88E6XXX_G2_SMI_PHY_CMD_OP_MASK 0x0c00
+#define MV88E6XXX_G2_SMI_PHY_CMD_OP_22_WRITE_DATA 0x0400
+#define MV88E6XXX_G2_SMI_PHY_CMD_OP_22_READ_DATA 0x0800
+#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_ADDR 0x0000
+#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_WRITE_DATA 0x0400
+#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA_INC 0x0800
+#define MV88E6XXX_G2_SMI_PHY_CMD_OP_45_READ_DATA 0x0c00
+#define MV88E6XXX_G2_SMI_PHY_CMD_DEV_ADDR_MASK 0x03e0
+#define MV88E6XXX_G2_SMI_PHY_CMD_REG_ADDR_MASK 0x001f
+#define MV88E6XXX_G2_SMI_PHY_CMD_SETUP_PTR_MASK 0x03ff
+
+/* Offset 0x19: SMI PHY Data Register */
+#define MV88E6XXX_G2_SMI_PHY_DATA 0x19
+
+/* Offset 0x14: EEPROM Command */
+#define MV88E6XXX_G2_EEPROM_CMD 0x14
+#define MV88E6XXX_G2_EEPROM_CMD_BUSY 0x8000
+#define MV88E6XXX_G2_EEPROM_CMD_OP_MASK 0x7000
+#define MV88E6XXX_G2_EEPROM_CMD_OP_WRITE 0x3000
+#define MV88E6XXX_G2_EEPROM_CMD_OP_READ 0x4000
+#define MV88E6XXX_G2_EEPROM_CMD_OP_LOAD 0x6000
+#define MV88E6XXX_G2_EEPROM_CMD_RUNNING 0x0800
+#define MV88E6XXX_G2_EEPROM_CMD_WRITE_EN 0x0400
+#define MV88E6352_G2_EEPROM_CMD_ADDR_MASK 0x00ff
+#define MV88E6390_G2_EEPROM_CMD_DATA_MASK 0x00ff
+
+/* Offset 0x15: EEPROM Data */
+#define MV88E6352_G2_EEPROM_DATA 0x15
+#define MV88E6352_G2_EEPROM_DATA_MASK 0xffff
+
+/* Offset 0x15: EEPROM Addr */
+#define MV88E6390_G2_EEPROM_ADDR 0x15
+#define MV88E6390_G2_EEPROM_ADDR_MASK 0xffff
+
+int mv88e6xxx_g2_read(struct mv88e6xxx_chip *chip, int reg, u16 *val);
+int mv88e6xxx_g2_write(struct mv88e6xxx_chip *chip, int reg, u16 val);
+int mv88e6xxx_g2_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask);
+
+int mv88e6xxx_g2_smi_phy_read(struct mv88e6xxx_chip *chip,
+ struct mii_bus *bus,
+ int addr, int reg, u16 *val);
+int mv88e6xxx_g2_smi_phy_write(struct mv88e6xxx_chip *chip,
+ struct mii_bus *bus,
+ int addr, int reg, u16 val);
+
+int mv88e6xxx_g2_get_eeprom8(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data);
+int mv88e6xxx_g2_set_eeprom8(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data);
+int mv88e6xxx_g2_get_eeprom16(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data);
+int mv88e6xxx_g2_set_eeprom16(struct mv88e6xxx_chip *chip,
+ struct ethtool_eeprom *eeprom, u8 *data);
+
+#endif /* _MV88E6XXX_GLOBAL2_H */
diff --git a/drivers/net/phy/mv88e6xxx/port.c b/drivers/net/phy/mv88e6xxx/port.c
new file mode 100644
index 0000000000..52f95d622c
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/port.c
@@ -0,0 +1,663 @@
+#include <common.h>
+#include <init.h>
+
+#include <linux/bitfield.h>
+#include <linux/marvell_phy.h>
+
+#include "port.h"
+
+int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
+ u16 *val)
+{
+ int addr = chip->info->port_base_addr + port;
+
+ return mv88e6xxx_read(chip, addr, reg, val);
+}
+
+int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
+ u16 val)
+{
+ int addr = chip->info->port_base_addr + port;
+
+ return mv88e6xxx_write(chip, addr, reg, val);
+}
+
+/* Offset 0x00: MAC (or PCS or Physical) Status Register
+ *
+ * For most devices, this is read only. However the 6185 has the MyPause
+ * bit read/write.
+ */
+int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
+ int pause)
+{
+ u16 reg;
+ int err;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+ if (err)
+ return err;
+
+ if (pause)
+ reg |= MV88E6XXX_PORT_STS_MY_PAUSE;
+ else
+ reg &= ~MV88E6XXX_PORT_STS_MY_PAUSE;
+
+ return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
+}
+
+/* Offset 0x01: MAC (or PCS or Physical) Control Register
+ *
+ * Link, Duplex and Flow Control have one force bit, one value bit.
+ *
+ * For port's MAC speed, ForceSpd (or SpdValue) bits 1:0 program the value.
+ * Alternative values require the 200BASE (or AltSpeed) bit 12 set.
+ * Newer chips need a ForcedSpd bit 13 set to consider the value.
+ */
+
+static int mv88e6xxx_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ u16 reg;
+ int err;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
+ if (err)
+ return err;
+
+ reg &= ~(MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
+ MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK);
+
+ switch (mode) {
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ reg |= MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK |
+ MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ break;
+ default:
+ return 0;
+ }
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+ if (err)
+ return err;
+
+ dev_dbg(chip->dev, "p%d: delay RXCLK %s, TXCLK %s\n", port,
+ reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK ? "yes" : "no",
+ reg & MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK ? "yes" : "no");
+
+ return 0;
+}
+
+int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ if (port < 5)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
+}
+
+int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ if (port != 0)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_rgmii_delay(chip, port, mode);
+}
+
+int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link)
+{
+ u16 reg;
+ int err;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
+ if (err)
+ return err;
+
+ reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
+ MV88E6XXX_PORT_MAC_CTL_LINK_UP);
+
+ switch (link) {
+ case LINK_FORCED_DOWN:
+ reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK;
+ break;
+ case LINK_FORCED_UP:
+ reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_LINK |
+ MV88E6XXX_PORT_MAC_CTL_LINK_UP;
+ break;
+ case LINK_UNFORCED:
+ /* normal link detection */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+ if (err)
+ return err;
+
+ dev_dbg(chip->dev, "p%d: %s link %s\n", port,
+ reg & MV88E6XXX_PORT_MAC_CTL_FORCE_LINK ? "Force" : "Unforce",
+ reg & MV88E6XXX_PORT_MAC_CTL_LINK_UP ? "up" : "down");
+
+ return 0;
+}
+
+int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup)
+{
+ u16 reg;
+ int err;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
+ if (err)
+ return err;
+
+ reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
+ MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL);
+
+ switch (dup) {
+ case DUPLEX_HALF:
+ reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX;
+ break;
+ case DUPLEX_FULL:
+ reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX |
+ MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL;
+ break;
+ case DUPLEX_UNFORCED:
+ /* normal duplex detection */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+ if (err)
+ return err;
+
+ dev_dbg(chip->dev, "p%d: %s %s duplex\n", port,
+ reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce",
+ reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half");
+
+ return 0;
+}
+
+static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port,
+ int speed, bool alt_bit, bool force_bit)
+{
+ u16 reg, ctrl;
+ int err;
+
+ switch (speed) {
+ case 10:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_10;
+ break;
+ case 100:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100;
+ break;
+ case 200:
+ if (alt_bit)
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_100 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ else
+ ctrl = MV88E6065_PORT_MAC_CTL_SPEED_200;
+ break;
+ case 1000:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000;
+ break;
+ case 2500:
+ ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 |
+ MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ break;
+ case 10000:
+ /* all bits set, fall through... */
+ case SPEED_UNFORCED:
+ ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, &reg);
+ if (err)
+ return err;
+
+ reg &= ~MV88E6XXX_PORT_MAC_CTL_SPEED_MASK;
+ if (alt_bit)
+ reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED;
+ if (force_bit) {
+ reg &= ~MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
+ if (speed != SPEED_UNFORCED)
+ ctrl |= MV88E6390_PORT_MAC_CTL_FORCE_SPEED;
+ }
+ reg |= ctrl;
+
+ err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg);
+ if (err)
+ return err;
+
+ if (speed)
+ dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed);
+ else
+ dev_dbg(chip->dev, "p%d: Speed unforced\n", port);
+
+ return 0;
+}
+
+/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
+int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
+{
+ if (speed == SPEED_MAX)
+ speed = 200;
+
+ if (speed > 200)
+ return -EOPNOTSUPP;
+
+ /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
+ return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
+}
+
+/* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
+int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
+{
+ if (speed == SPEED_MAX)
+ speed = 1000;
+
+ if (speed == 200 || speed > 1000)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
+}
+
+/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
+int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
+{
+ if (speed == SPEED_MAX)
+ speed = 1000;
+
+ if (speed > 1000)
+ return -EOPNOTSUPP;
+
+ if (speed == 200 && port < 5)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_speed(chip, port, speed, true, false);
+}
+
+/* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */
+int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
+{
+ if (speed == SPEED_MAX)
+ speed = port < 9 ? 1000 : 2500;
+
+ if (speed > 2500)
+ return -EOPNOTSUPP;
+
+ if (speed == 200 && port != 0)
+ return -EOPNOTSUPP;
+
+ if (speed == 2500 && port < 9)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
+}
+
+/* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
+int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
+{
+ if (speed == SPEED_MAX)
+ speed = port < 9 ? 1000 : 10000;
+
+ if (speed == 200 && port != 0)
+ return -EOPNOTSUPP;
+
+ if (speed >= 2500 && port < 9)
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_port_set_speed(chip, port, speed, true, true);
+}
+
+int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode)
+{
+ u16 cmode;
+
+ if (mode == PHY_INTERFACE_MODE_NA)
+ return 0;
+
+ if (port != 9 && port != 10)
+ return -EOPNOTSUPP;
+
+ switch (mode) {
+ case PHY_INTERFACE_MODE_1000BASEX:
+ cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
+ break;
+ case PHY_INTERFACE_MODE_XGMII:
+ case PHY_INTERFACE_MODE_XAUI:
+ cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
+ break;
+ case PHY_INTERFACE_MODE_RXAUI:
+ cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
+ break;
+ default:
+ cmode = 0;
+ }
+
+ chip->ports[port].cmode = cmode;
+
+ return 0;
+}
+
+int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state)
+{
+ int err;
+ u16 reg;
+
+ err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+ if (err)
+ return err;
+
+ switch (reg & MV88E6XXX_PORT_STS_SPEED_MASK) {
+ case MV88E6XXX_PORT_STS_SPEED_10:
+ state->speed = SPEED_10;
+ break;
+ case MV88E6XXX_PORT_STS_SPEED_100:
+ state->speed = SPEED_100;
+ break;
+ case MV88E6XXX_PORT_STS_SPEED_1000:
+ state->speed = SPEED_1000;
+ break;
+ case MV88E6XXX_PORT_STS_SPEED_10000:
+ if ((reg & MV88E6XXX_PORT_STS_CMODE_MASK) ==
+ MV88E6XXX_PORT_STS_CMODE_2500BASEX)
+ state->speed = SPEED_2500;
+ else
+ state->speed = SPEED_10000;
+ break;
+ }
+
+ state->duplex = reg & MV88E6XXX_PORT_STS_DUPLEX ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ state->link = !!(reg & MV88E6XXX_PORT_STS_LINK);
+ state->an_enabled = 1;
+ state->an_complete = state->link;
+
+ return 0;
+}
+
+int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state)
+{
+ if (state->interface == PHY_INTERFACE_MODE_1000BASEX) {
+ u8 cmode = chip->ports[port].cmode;
+
+ /* When a port is in "Cross-chip serdes" mode, it uses
+ * 1000Base-X full duplex mode, but there is no automatic
+ * link detection. Use the sync OK status for link (as it
+ * would do for 1000Base-X mode.)
+ */
+ if (cmode == MV88E6185_PORT_STS_CMODE_SERDES) {
+ u16 mac;
+ int err;
+
+ err = mv88e6xxx_port_read(chip, port,
+ MV88E6XXX_PORT_MAC_CTL, &mac);
+ if (err)
+ return err;
+
+ state->link = !!(mac & MV88E6185_PORT_MAC_CTL_SYNC_OK);
+ state->an_enabled = 1;
+ state->an_complete =
+ !!(mac & MV88E6185_PORT_MAC_CTL_AN_DONE);
+ state->duplex =
+ state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN;
+ state->speed =
+ state->link ? SPEED_1000 : SPEED_UNKNOWN;
+
+ return 0;
+ }
+ }
+
+ return mv88e6352_port_link_state(chip, port, state);
+}
+
+
+static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
+ int link, int speed, int duplex, int pause,
+ phy_interface_t mode)
+{
+ int err;
+
+ if (!chip->info->ops->port_set_link)
+ return 0;
+
+ /* Port's MAC control must not be changed unless the link is down */
+ err = chip->info->ops->port_set_link(chip, port, 0);
+ if (err)
+ return err;
+
+ if (chip->info->ops->port_set_speed) {
+ err = chip->info->ops->port_set_speed(chip, port, speed);
+ if (err && err != -EOPNOTSUPP)
+ goto restore_link;
+ }
+
+ if (chip->info->ops->port_set_pause) {
+ err = chip->info->ops->port_set_pause(chip, port, pause);
+ if (err)
+ goto restore_link;
+
+ }
+
+ if (chip->info->ops->port_set_duplex) {
+ err = chip->info->ops->port_set_duplex(chip, port, duplex);
+ if (err && err != -EOPNOTSUPP)
+ goto restore_link;
+ }
+
+ if (chip->info->ops->port_set_rgmii_delay) {
+ err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
+ if (err && err != -EOPNOTSUPP)
+ goto restore_link;
+ }
+
+ if (chip->info->ops->port_set_cmode) {
+ err = chip->info->ops->port_set_cmode(chip, port, mode);
+ if (err && err != -EOPNOTSUPP)
+ goto restore_link;
+ }
+
+ err = 0;
+restore_link:
+ if (chip->info->ops->port_set_link(chip, port, link))
+ dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
+
+ return err;
+}
+
+static int mv88e6xxx_port_config_init(struct phy_device *phydev)
+{
+ struct mv88e6xxx_chip *chip = phydev->dev.priv;
+ int port = phydev->addr - chip->info->port_base_addr;
+ int err;
+
+ err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
+ phydev->duplex, phydev->pause,
+ phydev->interface);
+
+ if (err && err != -EOPNOTSUPP)
+ dev_err(&phydev->dev, "p%d: failed to configure MAC\n", port);
+
+ return err;
+}
+
+static int mv88e6xxx_port_config_aneg(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static int mv88e6xxx_port_read_status(struct phy_device *phydev)
+{
+ struct mv88e6xxx_chip *chip = phydev->dev.priv;
+ int port = phydev->addr - chip->info->port_base_addr;
+ struct phylink_link_state state;
+ int err;
+
+ err = mv88e6352_port_link_state(chip, port, &state);
+ if (err)
+ return err;
+
+ phydev->link = state.link;
+ phydev->duplex = state.duplex;
+ phydev->speed = state.speed;
+
+ phydev->pause = phydev->asym_pause = 0;
+
+ return 0;
+}
+
+/*
+ * Fake switch PHY_ID used to match this driver against devices
+ * create in mv88e6xxx_port_probe.
+ */
+#define MV88E6XXX_SWITCH_PORT_PHY_ID (0x01410000 | \
+ MV88E6XXX_PORT_SWITCH_ID_PROD_6085)
+
+static struct phy_driver mv88e6xxx_port_driver = {
+ .phy_id = MV88E6XXX_SWITCH_PORT_PHY_ID,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .drv.name = "Marvel 88E6xxx Port",
+ .features = PHY_GBIT_FEATURES & ~SUPPORTED_Autoneg,
+ .config_init = mv88e6xxx_port_config_init,
+ .config_aneg = mv88e6xxx_port_config_aneg,
+ .read_status = mv88e6xxx_port_read_status,
+};
+
+static int __init mv88e6xxx_port_driver_register(void)
+{
+ return phy_driver_register(&mv88e6xxx_port_driver);
+}
+fs_initcall(mv88e6xxx_port_driver_register);
+
+int mv88e6xxx_port_probe(struct mv88e6xxx_chip *chip)
+{
+ struct device_d *dev = chip->dev;
+ struct device_node *np = dev->device_node;
+ struct device_node *port_node, *switch_node;
+ struct device_node *port_nodes[DSA_MAX_PORTS] = { NULL };
+ int err, i;
+
+ switch_node = of_find_node_by_name(np, "ports");
+ if (!switch_node)
+ return -EINVAL;
+
+ for_each_available_child_of_node(switch_node, port_node) {
+ u32 nr;
+
+ err = of_property_read_u32(port_node, "reg", &nr);
+ if (err) {
+ dev_err(dev,
+ "Error: Failed to find reg for child %s\n",
+ port_node->full_name);
+ continue;
+ }
+
+ port_nodes[nr] = port_node;
+ }
+
+ /*
+ * Walk through all of the ports and unmask those that are
+ * connected to a PHY via child MDIO bus, so the can be picked
+ * up via regular PHY discover.
+ *
+ * While at it, also create PHY objects for ports that are
+ * not, so they can be correctly configured
+ */
+ for (i = 0; i < chip->info->num_ports; i++) {
+ struct phy_device *phydev;
+ u16 status;
+ bool force_mac = false;
+ int addr = i;
+
+ err = mv88e6xxx_port_read(chip, i, MV88E6XXX_PORT_STS,
+ &status);
+ if (err)
+ return err;
+
+ /*
+ * FIXME: This most likely affects more than 6161, so
+ * this will have to be expanded to more chips
+ */
+ if (chip->info->prod_num ==
+ MV88E6XXX_PORT_SWITCH_ID_PROD_6161) {
+ const uint8_t cmode =
+ FIELD_GET(MV88E6185_PORT_STS_CMODE_MASK,
+ status);
+ switch (i) {
+ case 4:
+ case 5: /* FALLTHROUGH */
+ if (cmode == MV88E6165_PORT_STS_CMODE_SGMII) {
+ /*
+ * Port is configured to SGMII
+ * bypassing SERDES/PHY
+ */
+ force_mac = true;
+ break;
+ }
+
+ if (cmode != MV88E6165_PORT_STS_CMODE_PHY) {
+ /*
+ * If port is configured to
+ * SERDES we need to adjust
+ * its MDIO address
+ */
+ addr += MV88E6165_PORT_SERDES_OFFSET;
+ }
+
+ break;
+ }
+ }
+
+ if (status & MV88E6XXX_PORT_STS_PHY_DETECT && !force_mac) {
+ /*
+ * True PHYs will be automaticall handled by
+ * generic PHY driver, so we ignore those.
+ */
+ chip->miibus.phy_mask &= ~BIT(addr);
+ continue;
+ }
+
+ /*
+ * In order to expose MAC-only ports on the switch, so
+ * they can be properly configured to match other
+ * end's settings, we create pseudo PHY devices that
+ * will match against our special PHY driver
+ */
+ phydev = phy_device_create(chip->parent_miibus,
+ chip->info->port_base_addr + i,
+ MV88E6XXX_SWITCH_PORT_PHY_ID);
+ phydev->dev.device_node = port_nodes[i];
+ phydev->dev.priv = chip;
+ phydev->duplex = DUPLEX_UNFORCED;
+
+ err = phy_register_device(phydev);
+ if (err)
+ dev_err(dev, "Error: Failed to register a PHY\n");
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/drivers/net/phy/mv88e6xxx/port.h b/drivers/net/phy/mv88e6xxx/port.h
new file mode 100644
index 0000000000..07d937ecbd
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/port.h
@@ -0,0 +1,137 @@
+#ifndef _MV88E6XXX_PORT_H
+#define _MV88E6XXX_PORT_H
+
+#include "chip.h"
+
+/* Offset 0x00: Port Status Register */
+#define MV88E6XXX_PORT_STS 0x00
+#define MV88E6XXX_PORT_STS_PAUSE_EN 0x8000
+#define MV88E6XXX_PORT_STS_MY_PAUSE 0x4000
+#define MV88E6XXX_PORT_STS_HD_FLOW 0x2000
+#define MV88E6XXX_PORT_STS_PHY_DETECT 0x1000
+#define MV88E6XXX_PORT_STS_LINK 0x0800
+#define MV88E6XXX_PORT_STS_DUPLEX 0x0400
+#define MV88E6XXX_PORT_STS_SPEED_MASK 0x0300
+#define MV88E6XXX_PORT_STS_SPEED_10 0x0000
+#define MV88E6XXX_PORT_STS_SPEED_100 0x0100
+#define MV88E6XXX_PORT_STS_SPEED_1000 0x0200
+#define MV88E6XXX_PORT_STS_SPEED_10000 0x0300
+#define MV88E6352_PORT_STS_EEE 0x0040
+#define MV88E6165_PORT_STS_AM_DIS 0x0040
+#define MV88E6185_PORT_STS_MGMII 0x0040
+#define MV88E6XXX_PORT_STS_TX_PAUSED 0x0020
+#define MV88E6XXX_PORT_STS_FLOW_CTL 0x0010
+#define MV88E6XXX_PORT_STS_CMODE_MASK 0x000f
+#define MV88E6XXX_PORT_STS_CMODE_100BASE_X 0x0008
+#define MV88E6XXX_PORT_STS_CMODE_1000BASE_X 0x0009
+#define MV88E6XXX_PORT_STS_CMODE_SGMII 0x000a
+#define MV88E6XXX_PORT_STS_CMODE_2500BASEX 0x000b
+#define MV88E6XXX_PORT_STS_CMODE_XAUI 0x000c
+#define MV88E6XXX_PORT_STS_CMODE_RXAUI 0x000d
+#define MV88E6185_PORT_STS_CDUPLEX 0x0008
+#define MV88E6185_PORT_STS_CMODE_MASK 0x0007
+#define MV88E6185_PORT_STS_CMODE_GMII_FD 0x0000
+#define MV88E6185_PORT_STS_CMODE_MII_100_FD_PS 0x0001
+#define MV88E6185_PORT_STS_CMODE_MII_100 0x0002
+#define MV88E6185_PORT_STS_CMODE_MII_10 0x0003
+#define MV88E6185_PORT_STS_CMODE_SERDES 0x0004
+#define MV88E6165_PORT_STS_CMODE_PHY 0x0004
+#define MV88E6185_PORT_STS_CMODE_1000BASE_X 0x0005
+#define MV88E6185_PORT_STS_CMODE_PHY 0x0006
+#define MV88E6165_PORT_STS_CMODE_SGMII 0x0006
+#define MV88E6185_PORT_STS_CMODE_DISABLED 0x0007
+
+
+
+/* Offset 0x01: MAC (or PCS or Physical) Control Register */
+#define MV88E6XXX_PORT_MAC_CTL 0x01
+#define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK 0x8000
+#define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK 0x4000
+#define MV88E6185_PORT_MAC_CTL_SYNC_OK 0x4000
+#define MV88E6390_PORT_MAC_CTL_FORCE_SPEED 0x2000
+#define MV88E6390_PORT_MAC_CTL_ALTSPEED 0x1000
+#define MV88E6352_PORT_MAC_CTL_200BASE 0x1000
+#define MV88E6185_PORT_MAC_CTL_AN_EN 0x0400
+#define MV88E6185_PORT_MAC_CTL_AN_RESTART 0x0200
+#define MV88E6185_PORT_MAC_CTL_AN_DONE 0x0100
+#define MV88E6XXX_PORT_MAC_CTL_FC 0x0080
+#define MV88E6XXX_PORT_MAC_CTL_FORCE_FC 0x0040
+#define MV88E6XXX_PORT_MAC_CTL_LINK_UP 0x0020
+#define MV88E6XXX_PORT_MAC_CTL_FORCE_LINK 0x0010
+#define MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL 0x0008
+#define MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX 0x0004
+#define MV88E6XXX_PORT_MAC_CTL_SPEED_MASK 0x0003
+#define MV88E6XXX_PORT_MAC_CTL_SPEED_10 0x0000
+#define MV88E6XXX_PORT_MAC_CTL_SPEED_100 0x0001
+#define MV88E6065_PORT_MAC_CTL_SPEED_200 0x0002
+#define MV88E6XXX_PORT_MAC_CTL_SPEED_1000 0x0002
+#define MV88E6390_PORT_MAC_CTL_SPEED_10000 0x0003
+#define MV88E6XXX_PORT_MAC_CTL_SPEED_UNFORCED 0x0003
+
+/* Offset 0x03: Switch Identifier Register */
+#define MV88E6XXX_PORT_SWITCH_ID 0x03
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_MASK 0xfff0
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6085 0x04a0
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6095 0x0950
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6097 0x0990
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6190X 0x0a00
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6390X 0x0a10
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6131 0x1060
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6320 0x1150
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6123 0x1210
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6161 0x1610
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6165 0x1650
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6171 0x1710
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6172 0x1720
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6175 0x1750
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6176 0x1760
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6190 0x1900
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191 0x1910
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6185 0x1a70
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6290 0x2900
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6321 0x3100
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6141 0x3400
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6341 0x3410
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6352 0x3520
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6350 0x3710
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6351 0x3750
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6390 0x3900
+#define MV88E6XXX_PORT_SWITCH_ID_REV_MASK 0x000f
+
+
+/*
+ * SERDES connected to port 0x04 is accessible at address 0xC
+ */
+#define MV88E6165_PORT_SERDES_OFFSET (0x0C - 0x04)
+
+int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
+ u16 *val);
+int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
+ u16 val);
+
+int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
+ int pause);
+int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
+int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
+int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link);
+int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup);
+int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+ phy_interface_t mode);
+int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state);
+int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port,
+ struct phylink_link_state *state);
+
+/* Barebox specific */
+int mv88e6xxx_port_probe(struct mv88e6xxx_chip *chip);
+
+
+#endif /* _MV88E6XXX_PORT_H */
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 63f249fcff..7c4d14bf4c 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -176,12 +176,12 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id)
phydev->dev.bus = &mdio_bus_type;
if (bus) {
- sprintf(phydev->dev.name, "mdio%d-phy%02x",
- phydev->bus->dev.id,
- phydev->addr);
+ dev_set_name(&phydev->dev, "mdio%d-phy%02x",
+ phydev->bus->dev.id,
+ phydev->addr);
phydev->dev.id = DEVICE_ID_SINGLE;
} else {
- sprintf(phydev->dev.name, "fixed-phy");
+ dev_set_name(&phydev->dev, "fixed-phy");
phydev->dev.id = DEVICE_ID_DYNAMIC;
}
@@ -234,6 +234,10 @@ struct phy_device *get_phy_device(struct mii_bus *bus, int addr)
u32 phy_id = 0;
int r;
+ /* skip masked out PHY addresses */
+ if (bus->phy_mask & BIT(addr))
+ return ERR_PTR(-ENODEV);
+
r = get_phy_id(bus, addr, &phy_id);
if (r)
return ERR_PTR(r);
@@ -444,9 +448,6 @@ int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
}
for (i = 0; i < PHY_MAX_ADDR && !edev->phydev; i++) {
- /* skip masked out PHY addresses */
- if (bus->phy_mask & (1 << i))
- continue;
phy = mdiobus_scan(bus, i);
if (IS_ERR(phy))
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index c0f61f453a..63c0f997b3 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -199,7 +199,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->read_only = of_property_read_bool(np, "read-only") |
config->read_only;
- safe_strncpy(nvmem->dev.name, config->name, MAX_DRIVER_NAME);
+ dev_set_name(&nvmem->dev, config->name);
nvmem->dev.id = DEVICE_ID_DYNAMIC;
dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c
index ba35bef99a..e689559ee3 100644
--- a/drivers/nvmem/ocotp.c
+++ b/drivers/nvmem/ocotp.c
@@ -531,7 +531,7 @@ static int imx_ocotp_probe(struct device_d *dev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
- strcpy(priv->dev.name, "ocotp");
+ dev_set_name(&priv->dev, "ocotp");
priv->dev.parent = dev;
register_device(&priv->dev);
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 14db080417..4e12522a0a 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -379,8 +379,8 @@ static u64 __of_translate_address(struct device_node *dev,
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- dev->full_name);
+ pr_debug("prom_parse: Bad cell count for %s\n",
+ dev->full_name);
return OF_BAD_ADDR;
}
memcpy(addr, in_addr, na * 4);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index c9157cdd74..17052f4199 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -43,71 +43,35 @@ EXPORT_SYMBOL(of_find_device_by_node);
* of_device_make_bus_id - Use the device node data to assign a unique name
* @dev: pointer to device structure that is linked to a device tree node
*
- * This routine will first try using either the dcr-reg or the reg property
- * value to derive a unique name. As a last resort it will use the node
- * name followed by a unique number.
+ * This routine will first try using the translated bus address to
+ * derive a unique name. If it cannot, then it will prepend names from
+ * parent nodes until a unique name can be derived.
*/
static void of_device_make_bus_id(struct device_d *dev)
{
- static int bus_no_reg_magic;
- struct device_node *np = dev->device_node;
- const __be32 *reg, *addrp;
+ struct device_node *node = dev->device_node;
+ const __be32 *reg;
u64 addr;
- char *name, *at;
-
- name = xstrdup(np->name);
- at = strchr(name, '@');
- if (at)
- *at = '\0';
-
-#ifdef CONFIG_PPC_DCR
- /*
- * If it's a DCR based device, use 'd' for native DCRs
- * and 'D' for MMIO DCRs.
- */
- reg = of_get_property(np, "dcr-reg", NULL);
- if (reg) {
-#ifdef CONFIG_PPC_DCR_NATIVE
- snprintf(dev->name, MAX_DRIVER_NAME, "d%x.%s", *reg, name);
-#else /* CONFIG_PPC_DCR_NATIVE */
- u64 addr = of_translate_dcr_address(np, *reg, NULL);
- if (addr != OF_BAD_ADDR) {
- snprintf(dev->name, MAX_DRIVER_NAME, "D%llx.%s",
- (unsigned long long)addr, name);
- free(name);
- return;
- }
-#endif /* !CONFIG_PPC_DCR_NATIVE */
- }
-#endif /* CONFIG_PPC_DCR */
-
- /*
- * For MMIO, get the physical address
- */
- reg = of_get_property(np, "reg", NULL);
- if (reg) {
- if (of_can_translate_address(np)) {
- addr = of_translate_address(np, reg);
- } else {
- addrp = of_get_address(np, 0, NULL, NULL);
- if (addrp)
- addr = of_read_number(addrp, 1);
- else
- addr = OF_BAD_ADDR;
- }
- if (addr != OF_BAD_ADDR) {
- snprintf(dev->name, MAX_DRIVER_NAME, "%llx.%s",
- (unsigned long long)addr, name);
- free(name);
+
+ /* Construct the name, using parent nodes if necessary to ensure uniqueness */
+ while (node->parent) {
+ /*
+ * If the address can be translated, then that is as much
+ * uniqueness as we need. Make it the first component and return
+ */
+ reg = of_get_property(node, "reg", NULL);
+ if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
+ dev_set_name(dev, dev->name ? "%llx.%s:%s" : "%llx.%s",
+ (unsigned long long)addr, node->name,
+ dev->name);
return;
}
- }
- /*
- * No BusID, use the node name and add a globally incremented counter
- */
- snprintf(dev->name, MAX_DRIVER_NAME, "%s.%d", name, bus_no_reg_magic++);
- free(name);
+ /* format arguments only used if dev_name() resolves to NULL */
+ dev_set_name(dev, dev->name ? "%s:%s" : "%s",
+ kbasename(node->full_name), dev->name);
+ node = node->parent;
+ }
}
/**
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 201675b486..ac15623307 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -87,8 +87,7 @@ int pci_register_device(struct pci_dev *pdev)
struct device_d *dev = &pdev->dev;
int ret;
- snprintf(dev->name, MAX_DRIVER_NAME, "pci-%04x:%04x.",
- pdev->vendor, pdev->device);
+ dev_set_name(dev, "pci-%04x:%04x.", pdev->vendor, pdev->device);
dev->bus = &pci_bus;
dev->id = DEVICE_ID_DYNAMIC;
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 1b6a9f7b1d..9d6288fc07 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -46,7 +46,7 @@ struct phy *phy_create(struct device_d *dev, struct device_node *node,
id = phy_ida++;
- snprintf(phy->dev.name, MAX_DRIVER_NAME, "phy");
+ dev_set_name(&phy->dev, "phy");
phy->dev.id = id;
phy->dev.parent = dev;
phy->dev.device_node = node ?: dev->device_node;
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 80fade0611..c8016999f0 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -89,7 +89,7 @@ int pwmchip_add(struct pwm_chip *chip, struct device_d *dev)
pwm->chip = chip;
pwm->hwdev = dev;
- strcpy(pwm->dev.name, chip->devname);
+ dev_set_name(&pwm->dev, chip->devname);
pwm->dev.id = DEVICE_ID_SINGLE;
pwm->dev.parent = dev;
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 8b047a638d..5b58271c07 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -67,7 +67,7 @@ int rtc_register(struct rtc_device *rtcdev)
return -EINVAL;
dev->id = DEVICE_ID_DYNAMIC;
- strcpy(dev->name, "rtc");
+ dev_set_name(dev, "rtc");
if (rtcdev->dev)
dev->parent = rtcdev->dev;
platform_device_register(dev);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 5650098a0a..25bb988794 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -76,7 +76,7 @@ struct spi_device *spi_new_device(struct spi_master *master,
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);
+ dev_set_name(&proxy->dev, chip->name);
/* allocate a free id for this chip */
proxy->dev.id = DEVICE_ID_DYNAMIC;
proxy->dev.type_data = proxy;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 70ded6ded1..0ee8808a6b 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -431,9 +431,10 @@ int usb_new_device(struct usb_device *dev)
dev->serial, sizeof(dev->serial));
if (parent) {
- sprintf(dev->dev.name, "%s-%d", parent->dev.name, dev->portnr - 1);
+ dev_set_name(&dev->dev, "%s-%d", parent->dev.name,
+ dev->portnr - 1);
} else {
- sprintf(dev->dev.name, "usb%d", dev->host->busnum);
+ dev_set_name(&dev->dev, "usb%d", dev->host->busnum);
}
dev->dev.id = DEVICE_ID_SINGLE;
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index ed99b53df7..e357456098 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -179,7 +179,7 @@ int usb_add_gadget_udc_release(struct device_d *parent, struct usb_gadget *gadge
if (!udc)
goto err1;
- strcpy(gadget->dev.name, "usbgadget");
+ dev_set_name(&gadget->dev, "usbgadget");
gadget->dev.id = DEVICE_ID_SINGLE;
gadget->dev.parent = parent;
@@ -198,7 +198,7 @@ int usb_add_gadget_udc_release(struct device_d *parent, struct usb_gadget *gadge
dev_add_param_string(&gadget->dev, "productname", NULL, NULL,
&gadget->productname, NULL);
- strcpy(udc->dev.name, "udc");
+ dev_set_name(&udc->dev, "udc");
udc->dev.id = DEVICE_ID_DYNAMIC;
udc->gadget = gadget;
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 431b97ea9b..5fe3bcb7cd 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -333,7 +333,7 @@ static int dsps_register_otg_device(struct dsps_glue *glue)
{
int ret;
- strcpy(glue->otg_dev.name, "otg");
+ dev_set_name(&glue->otg_dev, "otg");
glue->otg_dev.id = DEVICE_ID_DYNAMIC,
glue->otg_dev.parent = glue->dev;
diff --git a/drivers/video/backlight.c b/drivers/video/backlight.c
index 30d52fcb68..3913d1c4c9 100644
--- a/drivers/video/backlight.c
+++ b/drivers/video/backlight.c
@@ -71,7 +71,7 @@ int backlight_register(struct backlight_device *bl)
{
int ret;
- sprintf(bl->dev.name, "backlight");
+ dev_set_name(&bl->dev, "backlight");
bl->dev.id = DEVICE_ID_DYNAMIC;
ret = register_device(&bl->dev);
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index c9d184d502..72f33a6db6 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -309,7 +309,7 @@ int register_framebuffer(struct fb_info *info)
dev->id = id;
dev->info = fb_info;
- sprintf(dev->name, "fb");
+ dev_set_name(dev, "fb");
ret = register_device(&info->dev);
if (ret)
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index ff573860ea..694ffa853e 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -423,7 +423,7 @@ static int w1_device_register(struct w1_bus *bus, struct w1_device *dev)
char str[18];
int ret;
- sprintf(dev->dev.name, "w1-%x-", dev->fid);
+ dev_set_name(&dev->dev, "w1-%x-", dev->fid);
dev->dev.id = DEVICE_ID_DYNAMIC;
dev->dev.bus = &w1_bustype;
dev->bus = bus;
@@ -619,7 +619,7 @@ int w1_bus_register(struct w1_bus *bus)
list_add_tail(&bus->list, &w1_buses);
- strcpy(bus->dev.name, "w1_bus");
+ dev_set_name(&bus->dev, "w1_bus");
bus->dev.id = DEVICE_ID_DYNAMIC;
bus->dev.parent = bus->parent;
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index 56e8626cb1..e6e5ddecd2 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -104,7 +104,7 @@ static int watchdog_register_dev(struct watchdog *wd, const char *name, int id)
{
wd->dev.parent = wd->hwdev;
wd->dev.id = id;
- strncpy(wd->dev.name, name, MAX_DRIVER_NAME);
+ dev_set_name(&wd->dev, name);
return register_device(&wd->dev);
}
diff --git a/fs/fs.c b/fs/fs.c
index 45750f7978..a30afa35f5 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2792,7 +2792,7 @@ int mount(const char *device, const char *fsname, const char *pathname,
fsdev = xzalloc(sizeof(struct fs_device_d));
fsdev->backingstore = xstrdup(device);
- safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME);
+ dev_set_name(&fsdev->dev, fsname);
fsdev->dev.id = get_free_deviceid(fsdev->dev.name);
fsdev->dev.bus = &fs_bus;
fsdev->options = xstrdup(fsoptions);
diff --git a/include/driver.h b/include/driver.h
index 63facbfbe5..7da184d3ab 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -23,7 +23,6 @@
#include <linux/ioport.h>
#include <of.h>
-#define MAX_DRIVER_NAME 32
#define FORMAT_DRIVER_NAME_ID "%s%d"
#include <param.h>
@@ -38,10 +37,19 @@ struct platform_device_id {
/** @brief Describes a particular device present in the system */
struct device_d {
- /*! This member (and 'type' described below) is used to match with a
- * driver. This is a descriptive name and could be MPC5XXX_ether or
- * imx_serial. */
- char name[MAX_DRIVER_NAME];
+ /*! This member (and 'type' described below) is used to match
+ * with a driver. This is a descriptive name and could be
+ * MPC5XXX_ether or imx_serial. Unless absolutely necessary,
+ * should not be modified directly and dev_set_name() should
+ * be used instead.
+ */
+ char *name;
+
+ /*! This member is used to store device's unique name as
+ * obtained by calling dev_id(). Internal field, do not
+ * access it directly.
+ */
+ char *unique_name;
/*! The id is used to uniquely identify a device in the system. The id
* will show up under /dev/ as the device's name. Usually this is
* something like eth0 or nor0. */
@@ -170,13 +178,18 @@ int get_free_deviceid(const char *name_template);
char *deviceid_from_spec_str(const char *str, char **endp);
-extern const char *dev_id(const struct device_d *dev);
+static inline const char *dev_id(const struct device_d *dev)
+{
+ return (dev->id != DEVICE_ID_SINGLE) ? dev->unique_name : dev->name;
+}
static inline const char *dev_name(const struct device_d *dev)
{
return dev_id(dev);
}
+int dev_set_name(struct device_d *dev, const char *fmt, ...);
+
/*
* get resource 'num' for a device
*/
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 4d83fe019e..324e40cdeb 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -72,9 +72,12 @@
#define SPEED_2500 2500
#define SPEED_10000 10000
+#define SPEED_UNKNOWN -1
+
/* Duplex, half or full. */
#define DUPLEX_HALF 0x00
#define DUPLEX_FULL 0x01
+#define DUPLEX_UNKNOWN 0xff
/* Which connector port. */
#define PORT_TP 0x00
diff --git a/include/linux/phy.h b/include/linux/phy.h
index ac750f5c3a..5b2c63ff69 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -54,7 +54,16 @@ typedef enum {
PHY_INTERFACE_MODE_RGMII_TXID,
PHY_INTERFACE_MODE_RTBI,
PHY_INTERFACE_MODE_SMII,
+ PHY_INTERFACE_MODE_XGMII,
PHY_INTERFACE_MODE_QSGMII,
+ PHY_INTERFACE_MODE_TRGMII,
+ PHY_INTERFACE_MODE_1000BASEX,
+ PHY_INTERFACE_MODE_2500BASEX,
+ PHY_INTERFACE_MODE_RXAUI,
+ PHY_INTERFACE_MODE_XAUI,
+ /* 10GBASE-KR, XFI, SFI - single lane 10G Serdes */
+ PHY_INTERFACE_MODE_10GKR,
+ PHY_INTERFACE_MODE_MAX,
} phy_interface_t;
#define PHY_INIT_TIMEOUT 100000
diff --git a/include/linux/string.h b/include/linux/string.h
index 90fe1b6ec8..fd42f5020a 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -111,6 +111,18 @@ extern char *strim(char *);
void *memchr_inv(const void *start, int c, size_t bytes);
+/**
+ * kbasename - return the last part of a pathname.
+ *
+ * @path: path to extract the filename from.
+ */
+static inline const char *kbasename(const char *path)
+{
+ const char *tail = strrchr(path, '/');
+ return tail ? tail + 1 : path;
+}
+
+
#ifdef __cplusplus
}
#endif
diff --git a/include/of.h b/include/of.h
index 7fc4b7791f..184acb4741 100644
--- a/include/of.h
+++ b/include/of.h
@@ -321,6 +321,12 @@ static inline int of_set_root_node(struct device_node *node)
return -ENOSYS;
}
+static inline struct device_d *of_platform_device_create(struct device_node *np,
+ struct device_d *parent)
+{
+ return NULL;
+}
+
static inline int of_n_addr_cells(struct device_node *np)
{
return 0;
diff --git a/lib/libgen.c b/lib/libgen.c
index 08ef3528af..61a8670fb5 100644
--- a/lib/libgen.c
+++ b/lib/libgen.c
@@ -17,23 +17,11 @@
#include <common.h>
#include <libgen.h>
+#include <linux/string.h>
char *basename (char *path)
{
- char *fname;
-
- if(!strchr(path, '/'))
- return path;
-
- fname = path + strlen(path) - 1;
- while (fname >= path) {
- if (*fname == '/') {
- fname++;
- break;
- }
- fname--;
- }
- return fname;
+ return (char *)kbasename(path);
}
EXPORT_SYMBOL(basename);
diff --git a/net/eth.c b/net/eth.c
index badd183433..b3e81247c2 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -364,7 +364,7 @@ int eth_register(struct eth_device *edev)
return -1;
}
- strcpy(edev->dev.name, "eth");
+ dev_set_name(&edev->dev, "eth");
if (edev->parent)
edev->dev.parent = edev->parent;