mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/16]
@ 2018-10-08  6:35 Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 01/16] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
                   ` (16 more replies)
  0 siblings, 17 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Everyone:

Patches in this series are a result of my work on porting Linux code
for MV88E6xxx switches to Barebox.

     - Patch 1 is loosely related header fix

     - Patch 2 adds clocksource support for ARM global time, needed on
       VF610 in order to get an accurate clocksource. MV88E6xxx EEPROM
       supporte code turned out to be dependent on that.

     - Pathes 3 and 4 are clocksource related fixes

     - Patches 5, 6, 7, 8 update the device naming scheme used by
       Barebox driver code. Old scheme couldn't handle devices created
       for DT nodes with identical names. This was the case on ZII
       VF610 Development Board Rev. C which had two switch devices.

    - Patch 9 is documentation/small code fix for generic MDIO bus
      code

    - Patches 10, 11 bring needed preprocessor constants from Linux kernel

    - Patch 12 prevents PHYs masked by MDIO bus's phy_maks from being
      probed

    - Patch 13 allows custom platform deviecs to be attached to an MDIO bus

    - Patch 14 exposes internal MDIO bus on MV88E6xxx devices

    - Patch 15 support for EEPROM devices attached to MV88E6xxx devices

    - Patch 16 exposes ports that don't have a PHY attached as
      "virtual" PHY devices (RPU2 needs this code to properly
      configure port connected to FEC)

NOTE: This is quite a mix and I am more than happy to split this
series in several if current patch grouping is problematic.

Tested on the following H/W:

     - ZII i.MX6Q RDU2, MV88E6352 switch
     - ZII i.MX51 RDU1, MV88E6161 switch
     - ZII i.MX7D RPU2, MV88E6352 switch
     - ZII VF610 CFU1, MV88E6352 switch
     - ZII VF610 SPU3, MV88E6390X switch
     - ZII VF610 Development Board Rev. C, MV88E6390X switch x 2

Feedback is welcome!

Thanks,
Andrey Smirnov

Andrey Smirnov (16):
  ARM: Do not expose ARMv8 functions on ARMv7
  clocksource: Add ARM global timer support
  i.MX: Move GPT driver to drivers/clocksource
  clocksource: Introduce ARCH_HAS_IMX_GPT
  of: Demote "Bad cell count for" to debug
  drivers: Introduce dev_set_name()
  linux: string: Port kbasename()
  of: Port latest of_device_make_bus_id() implementation
  mdio_bus: Fix documentation for mdio_bus_match()
  include: linux: phy: Add missing PHY_INTERFACE_* constants
  include: linux: ethtool: Add missing *_UNKNOWN constants
  net: phy: Check phy_mask in get_phy_device()
  mdio_bus: Allow for non PHY-devices on MDIO buses
  net: phy: Add basic driver for MV88E6XXX switches from Marvell
  net: phy: mv88e6xxx: Port EEPROM support code
  net: phy: mv88e6xxx: Add support for MAC ports

 arch/arm/include/asm/system.h                 |   2 +-
 arch/arm/mach-imx/Kconfig                     |  11 +
 arch/arm/mach-imx/Makefile                    |   1 -
 arch/arm/mach-imx/iim.c                       |   2 +-
 .../arm/mach-imx/include/mach/devices-imx51.h |   2 +-
 .../arm/mach-imx/include/mach/devices-imx53.h |   2 +-
 arch/arm/mach-mxs/include/mach/devices.h      |   2 +-
 arch/arm/mach-mxs/ocotp.c                     |   2 +-
 arch/sandbox/board/console.c                  |   2 +-
 common/console.c                              |   4 +-
 common/state/state.c                          |   2 +-
 drivers/aiodev/core.c                         |   2 +-
 drivers/amba/bus.c                            |   2 +-
 drivers/ata/disk_ata_drive.c                  |   4 +-
 drivers/base/bus.c                            |   2 +-
 drivers/base/driver.c                         |  38 +-
 drivers/base/resource.c                       |   2 +-
 drivers/clocksource/Kconfig                   |  11 +
 drivers/clocksource/Makefile                  |   2 +
 drivers/clocksource/arm_global_timer.c        | 113 +++
 .../clocksource/timer-imx-gpt.c               |   0
 drivers/efi/efi-device.c                      |   2 +-
 drivers/firmware/socfpga.c                    |   2 +-
 drivers/i2c/i2c.c                             |   4 +-
 drivers/mci/mci-core.c                        |   4 +-
 drivers/mfd/rave-sp.c                         |   2 +-
 drivers/mtd/core.c                            |   2 +-
 drivers/mtd/spi-nor/cadence-quadspi.c         |   2 +-
 drivers/mtd/ubi/build.c                       |   2 +-
 drivers/mtd/ubi/vmt.c                         |   4 +-
 drivers/net/cpsw.c                            |   2 +-
 drivers/net/e1000/eeprom.c                    |   2 +-
 drivers/net/orion-gbe.c                       |   2 +-
 drivers/net/phy/Kconfig                       |   6 +
 drivers/net/phy/Makefile                      |   1 +
 drivers/net/phy/mdio_bus.c                    |  24 +-
 drivers/net/phy/mv88e6xxx/Makefile            |   5 +
 drivers/net/phy/mv88e6xxx/chip.c              | 945 ++++++++++++++++++
 drivers/net/phy/mv88e6xxx/chip.h              | 143 +++
 drivers/net/phy/mv88e6xxx/global2.c           | 389 +++++++
 drivers/net/phy/mv88e6xxx/global2.h           |  70 ++
 drivers/net/phy/mv88e6xxx/port.c              | 666 ++++++++++++
 drivers/net/phy/mv88e6xxx/port.h              | 127 +++
 drivers/net/phy/phy.c                         |  15 +-
 drivers/nvmem/core.c                          |   2 +-
 drivers/nvmem/ocotp.c                         |   2 +-
 drivers/of/address.c                          |   4 +-
 drivers/of/platform.c                         |  80 +-
 drivers/pci/bus.c                             |   3 +-
 drivers/phy/phy-core.c                        |   2 +-
 drivers/pwm/core.c                            |   2 +-
 drivers/rtc/class.c                           |   2 +-
 drivers/spi/spi.c                             |   2 +-
 drivers/usb/core/usb.c                        |   5 +-
 drivers/usb/gadget/udc-core.c                 |   4 +-
 drivers/usb/musb/musb_dsps.c                  |   2 +-
 drivers/video/backlight.c                     |   2 +-
 drivers/video/fb.c                            |   2 +-
 drivers/w1/w1.c                               |   4 +-
 drivers/watchdog/wd_core.c                    |   2 +-
 fs/fs.c                                       |   2 +-
 include/driver.h                              |   5 +-
 include/linux/ethtool.h                       |   3 +
 include/linux/phy.h                           |   9 +
 include/linux/string.h                        |  12 +
 net/eth.c                                     |   2 +-
 66 files changed, 2653 insertions(+), 129 deletions(-)
 create mode 100644 drivers/clocksource/arm_global_timer.c
 rename arch/arm/mach-imx/clocksource.c => drivers/clocksource/timer-imx-gpt.c (100%)
 create mode 100644 drivers/net/phy/mv88e6xxx/Makefile
 create mode 100644 drivers/net/phy/mv88e6xxx/chip.c
 create mode 100644 drivers/net/phy/mv88e6xxx/chip.h
 create mode 100644 drivers/net/phy/mv88e6xxx/global2.c
 create mode 100644 drivers/net/phy/mv88e6xxx/global2.h
 create mode 100644 drivers/net/phy/mv88e6xxx/port.c
 create mode 100644 drivers/net/phy/mv88e6xxx/port.h

-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 01/16] ARM: Do not expose ARMv8 functions on ARMv7
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 02/16] clocksource: Add ARM global timer support Andrey Smirnov
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Assembly implementing current_el(), read_mpidr(), set_cntfrq(),
get_cntfrq() and get_cntpct() is ARMv8 specific, so change #if guard
protecting it to reflect that fact.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/include/asm/system.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 5cf828ea3..2f13e2b98 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;
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 02/16] clocksource: Add ARM global timer support
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 01/16] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  8:17   ` Sascha Hauer
  2018-10-08  6:35 ` [PATCH 03/16] i.MX: Move GPT driver to drivers/clocksource Andrey Smirnov
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port corresponding Linux kernel driver. Currently VFxxx SoC is the
intended consumer because it doesn't include common i.MX GPT block
used as clocksource by other i.MX SoCs.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/clocksource/Kconfig            |   4 +
 drivers/clocksource/Makefile           |   1 +
 drivers/clocksource/arm_global_timer.c | 113 +++++++++++++++++++++++++
 3 files changed, 118 insertions(+)
 create mode 100644 drivers/clocksource/arm_global_timer.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 3d63f7ff1..2be5a76b3 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -70,3 +70,7 @@ config CLOCKSOURCE_ARMV8_TIMER
 	bool
 	default y
 	depends on ARM && CPU_64v8
+
+config CLOCKSOURCE_ARM_GLOBAL_TIMER
+        def_bool y
+	depends on ARM
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index ea33fff50..51f6cb2f4 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -12,3 +12,4 @@ 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
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
new file mode 100644
index 000000000..44e3a3c76
--- /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);
+
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 03/16] i.MX: Move GPT driver to drivers/clocksource
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 01/16] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 02/16] clocksource: Add ARM global timer support Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 04/16] clocksource: Introduce ARCH_HAS_IMX_GPT Andrey Smirnov
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Move GPT driver to drivers/clocksource and rename it to
timer-imx-gpt.c to match Linux kernel as well as to keep all
clocksource drivers in a common location.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-imx/Makefile                                    | 1 -
 drivers/clocksource/Kconfig                                   | 4 ++++
 drivers/clocksource/Makefile                                  | 1 +
 .../clocksource.c => drivers/clocksource/timer-imx-gpt.c      | 0
 4 files changed, 5 insertions(+), 1 deletion(-)
 rename arch/arm/mach-imx/clocksource.c => drivers/clocksource/timer-imx-gpt.c (100%)

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 5a01dd57e..97c54406e 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/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 2be5a76b3..bb9d57f91 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -74,3 +74,7 @@ config CLOCKSOURCE_ARMV8_TIMER
 config CLOCKSOURCE_ARM_GLOBAL_TIMER
         def_bool y
 	depends on ARM
+
+config CLOCKSOURCE_IMX_GPT
+	def_bool y
+	depends on ARCH_IMX
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 51f6cb2f4..ce4d74137 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -13,3 +13,4 @@ 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/arch/arm/mach-imx/clocksource.c b/drivers/clocksource/timer-imx-gpt.c
similarity index 100%
rename from arch/arm/mach-imx/clocksource.c
rename to drivers/clocksource/timer-imx-gpt.c
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 04/16] clocksource: Introduce ARCH_HAS_IMX_GPT
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (2 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 03/16] i.MX: Move GPT driver to drivers/clocksource Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 05/16] of: Demote "Bad cell count for" to debug Andrey Smirnov
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Not all SoCs use i.MX GPT block as a clocksource, so introduce
ARCH_HAS_IMX_GPT to mark the ones that do.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-imx/Kconfig   | 11 +++++++++++
 drivers/clocksource/Kconfig |  5 ++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4a56fb9f4..cc8f65e1e 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -85,58 +85,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
@@ -164,6 +174,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
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index bb9d57f91..0e5978cbd 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
@@ -77,4 +80,4 @@ config CLOCKSOURCE_ARM_GLOBAL_TIMER
 
 config CLOCKSOURCE_IMX_GPT
 	def_bool y
-	depends on ARCH_IMX
+	depends on ARCH_HAS_IMX_GPT
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 05/16] of: Demote "Bad cell count for" to debug
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (3 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 04/16] clocksource: Introduce ARCH_HAS_IMX_GPT Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 06/16] drivers: Introduce dev_set_name() Andrey Smirnov
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

There are valid use-cases where getting OF_BAD_ADDR via that codepath
is expected. In addition to that analogous code in Linux kernel uses
pr_debug as well.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/of/address.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/of/address.c b/drivers/of/address.c
index 14db08041..4e12522a0 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);
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 06/16] drivers: Introduce dev_set_name()
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (4 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 05/16] of: Demote "Bad cell count for" to debug Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-09 15:41   ` Sam Ravnborg
  2018-10-08  6:35 ` [PATCH 07/16] linux: string: Port kbasename() Andrey Smirnov
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

In order to allow device names that are longer than MAX_DRIVER_NAME,
port Linux kernel function of the same name, and convert all of the
code to use it.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-imx/iim.c                       |  2 +-
 .../arm/mach-imx/include/mach/devices-imx51.h |  2 +-
 .../arm/mach-imx/include/mach/devices-imx53.h |  2 +-
 arch/arm/mach-mxs/include/mach/devices.h      |  2 +-
 arch/arm/mach-mxs/ocotp.c                     |  2 +-
 arch/sandbox/board/console.c                  |  2 +-
 common/console.c                              |  4 +-
 common/state/state.c                          |  2 +-
 drivers/aiodev/core.c                         |  2 +-
 drivers/amba/bus.c                            |  2 +-
 drivers/ata/disk_ata_drive.c                  |  4 +-
 drivers/base/bus.c                            |  2 +-
 drivers/base/driver.c                         | 38 +++++++++++++++++--
 drivers/base/resource.c                       |  2 +-
 drivers/efi/efi-device.c                      |  2 +-
 drivers/firmware/socfpga.c                    |  2 +-
 drivers/i2c/i2c.c                             |  4 +-
 drivers/mci/mci-core.c                        |  4 +-
 drivers/mfd/rave-sp.c                         |  2 +-
 drivers/mtd/core.c                            |  2 +-
 drivers/mtd/spi-nor/cadence-quadspi.c         |  2 +-
 drivers/mtd/ubi/build.c                       |  2 +-
 drivers/mtd/ubi/vmt.c                         |  4 +-
 drivers/net/cpsw.c                            |  2 +-
 drivers/net/e1000/eeprom.c                    |  2 +-
 drivers/net/orion-gbe.c                       |  2 +-
 drivers/net/phy/mdio_bus.c                    |  2 +-
 drivers/net/phy/phy.c                         |  8 ++--
 drivers/nvmem/core.c                          |  2 +-
 drivers/nvmem/ocotp.c                         |  2 +-
 drivers/of/platform.c                         | 12 +++---
 drivers/pci/bus.c                             |  3 +-
 drivers/phy/phy-core.c                        |  2 +-
 drivers/pwm/core.c                            |  2 +-
 drivers/rtc/class.c                           |  2 +-
 drivers/spi/spi.c                             |  2 +-
 drivers/usb/core/usb.c                        |  5 ++-
 drivers/usb/gadget/udc-core.c                 |  4 +-
 drivers/usb/musb/musb_dsps.c                  |  2 +-
 drivers/video/backlight.c                     |  2 +-
 drivers/video/fb.c                            |  2 +-
 drivers/w1/w1.c                               |  4 +-
 drivers/watchdog/wd_core.c                    |  2 +-
 fs/fs.c                                       |  2 +-
 include/driver.h                              |  5 ++-
 net/eth.c                                     |  2 +-
 46 files changed, 99 insertions(+), 66 deletions(-)

diff --git a/arch/arm/mach-imx/iim.c b/arch/arm/mach-imx/iim.c
index d4794cbac..207e1879c 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 cccd8f461..66fe643f8 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 10caae8c9..27200a26d 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 5680d61c9..b212aa783 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 b41fde991..01db73116 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 cf1781d15..006bbd1a6 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 40c26b66d..47ccf2e54 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 25d950211..55804a521 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 79f935d71..cb53cfb7d 100644
--- a/drivers/aiodev/core.c
+++ b/drivers/aiodev/core.c
@@ -115,7 +115,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/amba/bus.c b/drivers/amba/bus.c
index ae5df13c9..a8cd16835 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 5ebddbdec..11f7151e5 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 b889a4866..1038d20a1 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 c43a4bde2..fb73be066 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -468,16 +468,48 @@ EXPORT_SYMBOL(dummy_probe);
 
 const char *dev_id(const struct device_d *dev)
 {
-	static char buf[MAX_DRIVER_NAME + 16];
+	static char *buf;
+	int err;
+
+	if (buf)
+		free(buf);
 
 	if (dev->id != DEVICE_ID_SINGLE)
-		snprintf(buf, sizeof(buf), FORMAT_DRIVER_NAME_ID, dev->name, dev->id);
+		err = asprintf(&buf, FORMAT_DRIVER_NAME_ID,
+			       dev->name, dev->id);
 	else
-		snprintf(buf, sizeof(buf), "%s", dev->name);
+		err = asprintf(&buf, "%s", dev->name);
+
+	BUG_ON(err < 0);
 
 	return buf;
 }
 
+int dev_set_name(struct device_d *dev, const char *fmt, ...)
+{
+	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 on of vargs
+	 */
+	free(oldname);
+
+	WARN_ON(err < 0);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(dev_set_name);
+
 static void devices_shutdown(void)
 {
 	struct device_d *dev;
diff --git a/drivers/base/resource.c b/drivers/base/resource.c
index 6c2d7fed4..cb7105bf8 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/efi/efi-device.c b/drivers/efi/efi-device.c
index 3a27323a0..b7dea7c82 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 c1eae98ac..6d11da32a 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 608f8289b..25e0fe7ad 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 c6b4e02cb..c8d1d5e16 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/mfd/rave-sp.c b/drivers/mfd/rave-sp.c
index c61443218..40fce077c 100644
--- a/drivers/mfd/rave-sp.c
+++ b/drivers/mfd/rave-sp.c
@@ -789,7 +789,7 @@ static int rave_sp_add_params(struct rave_sp *sp)
 	int ret;
 
 	dev->parent = sp->serdev->dev;
-	strcpy(dev->name, "sp");
+	dev_set_name(dev, "sp");
 	dev->id = DEVICE_ID_SINGLE;
 
 	ret = register_device(dev);
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index ae7818a18..9ceceff16 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -610,7 +610,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 626966818..ed5377bd4 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 536077ebf..493c778c3 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 617704821..99da79171 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 3d3939cfa..c6fc21dc5 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 dda022e05..180b32ede 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 e6bd75768..431ec5c31 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/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 7d53bcc3d..177d54863 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -222,7 +222,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;
 
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 42dcad906..19d458e07 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;
 	}
 
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index c0f61f453..63c0f997b 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 c2d2982ee..0d07da280 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/platform.c b/drivers/of/platform.c
index c9157cdd7..4fd3ce2b7 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -68,12 +68,12 @@ static void of_device_make_bus_id(struct device_d *dev)
 	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);
+		dev_set_name(dev, "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);
+			dev_set_name(dev, "D%llx.%s",
+				     (unsigned long long)addr, name);
 			free(name);
 			return;
 		}
@@ -96,8 +96,8 @@ static void of_device_make_bus_id(struct device_d *dev)
 				addr = OF_BAD_ADDR;
 		}
 		if (addr != OF_BAD_ADDR) {
-			snprintf(dev->name, MAX_DRIVER_NAME, "%llx.%s",
-				(unsigned long long)addr, name);
+			dev_set_name(dev, "%llx.%s",
+				     (unsigned long long)addr, name);
 			free(name);
 			return;
 		}
@@ -106,7 +106,7 @@ static void of_device_make_bus_id(struct device_d *dev)
 	/*
 	 * 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++);
+	dev_set_name(dev, "%s.%d", name, bus_no_reg_magic++);
 	free(name);
 }
 
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 201675b48..ac1562330 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 1b6a9f7b1..9d6288fc0 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 80fade061..c8016999f 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 8b047a638..5b58271c0 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 5650098a0..25bb98879 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 70ded6ded..0ee8808a6 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 ed99b53df..e35745609 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 431b97ea9..5fe3bcb7c 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 30d52fcb6..3913d1c4c 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 c9d184d50..72f33a6db 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 ff573860e..694ffa853 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 56e8626cb..e6e5ddecd 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 2a4d78c9d..fdb58f6a3 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2716,7 +2716,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 1b61f2066..7b83c0a77 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>
@@ -41,7 +40,7 @@ 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];
+	char *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. */
@@ -177,6 +176,8 @@ 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/net/eth.c b/net/eth.c
index 9dc441195..36260478d 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -363,7 +363,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;
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 07/16] linux: string: Port kbasename()
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (5 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 06/16] drivers: Introduce dev_set_name() Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 08/16] of: Port latest of_device_make_bus_id() implementation Andrey Smirnov
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/linux/string.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index ed4eeb551..8479a3f57 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
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 08/16] of: Port latest of_device_make_bus_id() implementation
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (6 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 07/16] linux: string: Port kbasename() Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 09/16] mdio_bus: Fix documentation for mdio_bus_match() Andrey Smirnov
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Code implementing of_device_make_bus_id() in Barebox uses rather old
implementation from Linux kernel and has a very significan limitation
in that it will produce identical names for different DT nodes that
happen to have the same node name as well as "reg" property.

One such example, that tirggered this change, is "switch@0" nodes that
can be found in dts/src/arm/vf610-zii-dev-rev-c.dts

This commit replaces original code with the current Linux kernel
implementation that traverses DT hierarchy from leaf node to its root
concatenating node names in the process.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/of/platform.c | 80 ++++++++++++-------------------------------
 1 file changed, 22 insertions(+), 58 deletions(-)

diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 4fd3ce2b7..17052f419 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
-		dev_set_name(dev, "d%x.%s", *reg, name);
-#else /* CONFIG_PPC_DCR_NATIVE */
-		u64 addr = of_translate_dcr_address(np, *reg, NULL);
-		if (addr != OF_BAD_ADDR) {
-			dev_set_name(dev, "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) {
-			dev_set_name(dev, "%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
-	 */
-	dev_set_name(dev, "%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;
+	}
 }
 
 /**
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 09/16] mdio_bus: Fix documentation for mdio_bus_match()
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (7 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 08/16] of: Port latest of_device_make_bus_id() implementation Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 10/16] include: linux: phy: Add missing PHY_INTERFACE_* constants Andrey Smirnov
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Fix documentation for mdio_bus_match(), while at it re-arrange the
code to be easier to follow. Seeing != used as a result of a matching
function is extremely confusing.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/phy/mdio_bus.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 177d54863..d7d6d8940 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -335,16 +335,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)
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 10/16] include: linux: phy: Add missing PHY_INTERFACE_* constants
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (8 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 09/16] mdio_bus: Fix documentation for mdio_bus_match() Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 11/16] include: linux: ethtool: Add missing *_UNKNOWN constants Andrey Smirnov
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/linux/phy.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/include/linux/phy.h b/include/linux/phy.h
index ac750f5c3..5b2c63ff6 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
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 11/16] include: linux: ethtool: Add missing *_UNKNOWN constants
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (9 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 10/16] include: linux: phy: Add missing PHY_INTERFACE_* constants Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 12/16] net: phy: Check phy_mask in get_phy_device() Andrey Smirnov
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/linux/ethtool.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 4d83fe019..324e40cde 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
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 12/16] net: phy: Check phy_mask in get_phy_device()
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (10 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 11/16] include: linux: ethtool: Add missing *_UNKNOWN constants Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 13/16] mdio_bus: Allow for non PHY-devices on MDIO buses Andrey Smirnov
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Do not try to probe PHY devices if they are masked via phy_mask of the
corresponding bus. This way we won't try adding devices that are
unlikely to be proper PHYs by default. With this change it is still
remain to be possible to add such a device to the bus explicitly
either using "miitool" or calling phy_device_create() explicilty.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/phy/phy.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 19d458e07..b985b7567 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -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);
@@ -440,9 +444,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))
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 13/16] mdio_bus: Allow for non PHY-devices on MDIO buses
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (11 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 12/16] net: phy: Check phy_mask in get_phy_device() Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  8:44   ` Sascha Hauer
  2018-10-08  6:35 ` [PATCH 14/16] net: phy: Add basic driver for MV88E6XXX switches from Marvell Andrey Smirnov
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Instead of just creating a simple PHY device for every child of MDIO
bus node, add code to check if any of them have "compatible" property
set as well as code to create a proper platform device for such cases.

This change is useful for when MDIO bus and some of Ethernet ports are
connected to a switch or some other MDIO device that doesn't behave
like a generic PHY and can't be probed via its PHY ID.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/phy/mdio_bus.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index d7d6d8940..589ed57d2 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,6 +180,16 @@ 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_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;
+		}
+
 		if (!of_mdiobus_child_is_phy(child))
 			continue;
 
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 14/16] net: phy: Add basic driver for MV88E6XXX switches from Marvell
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (12 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 13/16] mdio_bus: Allow for non PHY-devices on MDIO buses Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 15/16] net: phy: mv88e6xxx: Port EEPROM support code Andrey Smirnov
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port a very abridged version of MV88E6XXX DSA driver from Linux
kernel. Currently only internal MDIO bus connected to switch PHYs is
exposed.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>

net: phy: mv88e6xxx: Expose internal MDIO bus
---
 drivers/net/phy/Kconfig             |   6 +
 drivers/net/phy/Makefile            |   1 +
 drivers/net/phy/mv88e6xxx/Makefile  |   5 +
 drivers/net/phy/mv88e6xxx/chip.c    | 724 ++++++++++++++++++++++++++++
 drivers/net/phy/mv88e6xxx/chip.h    |  61 +++
 drivers/net/phy/mv88e6xxx/global2.c | 124 +++++
 drivers/net/phy/mv88e6xxx/global2.h |  41 ++
 drivers/net/phy/mv88e6xxx/port.c    |  20 +
 drivers/net/phy/mv88e6xxx/port.h    |  89 ++++
 9 files changed, 1071 insertions(+)
 create mode 100644 drivers/net/phy/mv88e6xxx/Makefile
 create mode 100644 drivers/net/phy/mv88e6xxx/chip.c
 create mode 100644 drivers/net/phy/mv88e6xxx/chip.h
 create mode 100644 drivers/net/phy/mv88e6xxx/global2.c
 create mode 100644 drivers/net/phy/mv88e6xxx/global2.h
 create mode 100644 drivers/net/phy/mv88e6xxx/port.c
 create mode 100644 drivers/net/phy/mv88e6xxx/port.h

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 79fb917ee..3b1a6ea7e 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 4424054d9..e4d9ec65a 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/mv88e6xxx/Makefile b/drivers/net/phy/mv88e6xxx/Makefile
new file mode 100644
index 000000000..8c8ba78cd
--- /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
\ No newline at end of file
diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
new file mode 100644
index 000000000..cde60f43c
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/chip.c
@@ -0,0 +1,724 @@
+#include <common.h>
+#include <init.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/bitfield.h>
+
+#include <gpio.h>
+#include <of_device.h>
+#include <of_gpio.h>
+
+#include "chip.h"
+#include "global2.h"
+#include "port.h"
+
+/* #define MV88E6XXX_SWITCH_GLOBAL_REGS_3		0x1d */
+
+/* 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,
+};
+
+static const struct mv88e6xxx_ops mv88e6123_ops = {
+	/* MV88E6XXX_FAMILY_6165 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+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 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6161_ops = {
+	/* MV88E6XXX_FAMILY_6165 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+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,
+};
+
+static const struct mv88e6xxx_ops mv88e6172_ops = {
+	/* MV88E6XXX_FAMILY_6352 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6175_ops = {
+	/* MV88E6XXX_FAMILY_6351 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6176_ops = {
+	/* MV88E6XXX_FAMILY_6352 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+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 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6190x_ops = {
+	/* MV88E6XXX_FAMILY_6390 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6191_ops = {
+	/* MV88E6XXX_FAMILY_6390 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6240_ops = {
+	/* MV88E6XXX_FAMILY_6352 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6290_ops = {
+	/* MV88E6XXX_FAMILY_6390 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6320_ops = {
+	/* MV88E6XXX_FAMILY_6320 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6321_ops = {
+	/* MV88E6XXX_FAMILY_6320 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6341_ops = {
+	/* MV88E6XXX_FAMILY_6341 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6350_ops = {
+	/* MV88E6XXX_FAMILY_6351 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6351_ops = {
+	/* MV88E6XXX_FAMILY_6351 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6352_ops = {
+	/* MV88E6XXX_FAMILY_6352 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6390_ops = {
+	/* MV88E6XXX_FAMILY_6390 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+static const struct mv88e6xxx_ops mv88e6390x_ops = {
+	/* MV88E6XXX_FAMILY_6390 */
+	.phy_read = mv88e6xxx_g2_smi_phy_read,
+	.phy_write = mv88e6xxx_g2_smi_phy_write,
+};
+
+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_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;
+	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;
+	chip->info = of_device_get_match_data(dev);
+
+	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;
+	/*
+	 * In single-chip address mode addresses 0x10 - 0x1f are
+	 * reserved to access various switch registers and do not
+	 * correspond to any PHYs, so we mask them to pervent from
+	 * being exposed as phy devices
+	 */
+	chip->parent_miibus->phy_mask |= GENMASK(0x1f, 0x10);
+	/*
+	 * Address 0x0f on internal bus is dedicated to SERDES
+	 * registers and won't be very useful against standard PHY
+	 * driver
+	 */
+	chip->miibus.phy_mask |= GENMASK(0x1f, 0x0f);
+
+	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;
+
+	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 000000000..4df18a241
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/chip.h
@@ -0,0 +1,61 @@
+#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;
+
+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_chip {
+	const struct mv88e6xxx_info *info;
+	struct mii_bus *parent_miibus;
+	struct mii_bus miibus;
+	struct device_d *dev;
+	int reset;
+};
+
+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 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 */
\ No newline at end of file
diff --git a/drivers/net/phy/mv88e6xxx/global2.c b/drivers/net/phy/mv88e6xxx/global2.c
new file mode 100644
index 000000000..fc78049aa
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/global2.c
@@ -0,0 +1,124 @@
+#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);
+}
+
+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 000000000..28bbd8c43
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/global2.h
@@ -0,0 +1,41 @@
+#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
+
+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);
+
+#endif /* _MV88E6XXX_GLOBAL2_H */
\ No newline at end of file
diff --git a/drivers/net/phy/mv88e6xxx/port.c b/drivers/net/phy/mv88e6xxx/port.c
new file mode 100644
index 000000000..59afdbd97
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/port.c
@@ -0,0 +1,20 @@
+#include <common.h>
+#include <init.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);
+}
diff --git a/drivers/net/phy/mv88e6xxx/port.h b/drivers/net/phy/mv88e6xxx/port.h
new file mode 100644
index 000000000..84c76c42c
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/port.h
@@ -0,0 +1,89 @@
+#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 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
+
+/* 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 MV88E6390_PORT_MAC_CTL_FORCE_SPEED		0x2000
+#define MV88E6390_PORT_MAC_CTL_ALTSPEED			0x1000
+#define MV88E6352_PORT_MAC_CTL_200BASE			0x1000
+#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
+
+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);
+
+
+#endif /* _MV88E6XXX_PORT_H */
\ No newline at end of file
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 15/16] net: phy: mv88e6xxx: Port EEPROM support code
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (13 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 14/16] net: phy: Add basic driver for MV88E6XXX switches from Marvell Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-08  6:35 ` [PATCH 16/16] net: phy: mv88e6xxx: Add support for MAC ports Andrey Smirnov
  2018-10-09 17:30 ` [PATCH 00/16] Andrey Smirnov
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/phy/mv88e6xxx/chip.c    |  85 ++++++++-
 drivers/net/phy/mv88e6xxx/chip.h    |  10 ++
 drivers/net/phy/mv88e6xxx/global2.c | 265 ++++++++++++++++++++++++++++
 drivers/net/phy/mv88e6xxx/global2.h |  29 +++
 4 files changed, 388 insertions(+), 1 deletion(-)

diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
index cde60f43c..162acf1cc 100644
--- a/drivers/net/phy/mv88e6xxx/chip.c
+++ b/drivers/net/phy/mv88e6xxx/chip.c
@@ -4,6 +4,7 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/bitfield.h>
+#include <linux/nvmem-provider.h>
 
 #include <gpio.h>
 #include <of_device.h>
@@ -80,6 +81,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
 
 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,
 };
@@ -105,6 +108,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
 
 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,
 };
@@ -117,6 +122,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
 
 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,
 };
@@ -130,48 +137,64 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
 
 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,
 };
 
 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,
 };
 
 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,
 };
 
 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,
 };
 
 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,
 };
 
 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,
 };
 
 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,
 };
 
 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,
 };
@@ -192,16 +215,22 @@ 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,
 };
 
 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,
 };
 
 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,
 };
@@ -622,6 +651,41 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *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;
@@ -629,7 +693,7 @@ static int mv88e6xxx_probe(struct device_d *dev)
 	struct mv88e6xxx_chip *chip;
 	enum of_gpio_flags of_flags;
 	int err;
-	u32 reg;
+	u32 reg, eeprom_len = 0;
 
 	err = of_property_read_u32(np, "reg", &reg);
 	if (err) {
@@ -644,8 +708,11 @@ static int mv88e6xxx_probe(struct device_d *dev)
 
 	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;
@@ -677,6 +744,22 @@ static int mv88e6xxx_probe(struct device_d *dev)
 	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 - 0x1f are
 	 * reserved to access various switch registers and do not
diff --git a/drivers/net/phy/mv88e6xxx/chip.h b/drivers/net/phy/mv88e6xxx/chip.h
index 4df18a241..021df2664 100644
--- a/drivers/net/phy/mv88e6xxx/chip.h
+++ b/drivers/net/phy/mv88e6xxx/chip.h
@@ -45,6 +45,11 @@ struct mv88e6xxx_chip {
 	int reset;
 };
 
+struct ethtool_eeprom {
+	__u32	offset;
+	__u32	len;
+};
+
 struct mv88e6xxx_ops {
 	int (*phy_read)(struct mv88e6xxx_chip *chip,
 			struct mii_bus *bus,
@@ -52,6 +57,11 @@ struct mv88e6xxx_ops {
 	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);
 };
 
 int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
diff --git a/drivers/net/phy/mv88e6xxx/global2.c b/drivers/net/phy/mv88e6xxx/global2.c
index fc78049aa..0e8f2c5ee 100644
--- a/drivers/net/phy/mv88e6xxx/global2.c
+++ b/drivers/net/phy/mv88e6xxx/global2.c
@@ -18,6 +18,271 @@ 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,
diff --git a/drivers/net/phy/mv88e6xxx/global2.h b/drivers/net/phy/mv88e6xxx/global2.h
index 28bbd8c43..7c70d4bde 100644
--- a/drivers/net/phy/mv88e6xxx/global2.h
+++ b/drivers/net/phy/mv88e6xxx/global2.h
@@ -27,6 +27,26 @@
 /* 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);
@@ -38,4 +58,13 @@ 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 */
\ No newline at end of file
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 16/16] net: phy: mv88e6xxx: Add support for MAC ports
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (14 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 15/16] net: phy: mv88e6xxx: Port EEPROM support code Andrey Smirnov
@ 2018-10-08  6:35 ` Andrey Smirnov
  2018-10-09 17:30 ` [PATCH 00/16] Andrey Smirnov
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08  6:35 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/phy/mv88e6xxx/chip.c | 146 ++++++-
 drivers/net/phy/mv88e6xxx/chip.h |  72 ++++
 drivers/net/phy/mv88e6xxx/port.c | 646 +++++++++++++++++++++++++++++++
 drivers/net/phy/mv88e6xxx/port.h |  38 ++
 4 files changed, 898 insertions(+), 4 deletions(-)

diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
index 162acf1cc..5a8947f8b 100644
--- a/drivers/net/phy/mv88e6xxx/chip.c
+++ b/drivers/net/phy/mv88e6xxx/chip.c
@@ -64,12 +64,20 @@ 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 = {
@@ -85,12 +93,20 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
 	.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 = {
@@ -104,6 +120,11 @@ 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 = {
@@ -112,12 +133,22 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
 	.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 = {
@@ -126,6 +157,11 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
 	.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 = {
@@ -141,6 +177,11 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
 	.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 = {
@@ -149,6 +190,11 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
 	.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 = {
@@ -157,6 +203,11 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
 	.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 = {
@@ -165,6 +216,11 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
 	.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 = {
@@ -173,6 +229,11 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
 	.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 = {
@@ -181,6 +242,10 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
 	.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 = {
@@ -189,6 +254,10 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
 	.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 = {
@@ -197,18 +266,33 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
 	.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 = {
@@ -217,6 +301,11 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
 	.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 = {
@@ -225,6 +314,12 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
 	.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 = {
@@ -233,6 +328,12 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
 	.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[] = {
@@ -241,6 +342,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6097,
 		.name = "Marvell 88E6085",
 		.num_ports = 10,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6085_ops,
@@ -251,6 +353,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6095,
 		.name = "Marvell 88E6095/88E6095F",
 		.num_ports = 11,
+		.num_internal_phys = 0,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6095_ops,
@@ -261,6 +364,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6097,
 		.name = "Marvell 88E6097/88E6097F",
 		.num_ports = 11,
+		.num_internal_phys = 8,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6097_ops,
@@ -271,6 +375,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6165,
 		.name = "Marvell 88E6123",
 		.num_ports = 3,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6123_ops,
@@ -281,6 +386,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6185,
 		.name = "Marvell 88E6131",
 		.num_ports = 8,
+		.num_internal_phys = 0,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6131_ops,
@@ -291,6 +397,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6341,
 		.name = "Marvell 88E6341",
 		.num_ports = 6,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6141_ops,
@@ -301,6 +408,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6165,
 		.name = "Marvell 88E6161",
 		.num_ports = 6,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6161_ops,
@@ -311,6 +419,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6165,
 		.name = "Marvell 88E6165",
 		.num_ports = 6,
+		.num_internal_phys = 0,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6165_ops,
@@ -321,6 +430,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6171",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6171_ops,
@@ -331,6 +441,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6172",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6172_ops,
@@ -341,6 +452,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6175",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6175_ops,
@@ -351,6 +463,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6176",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6176_ops,
@@ -361,6 +474,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6185,
 		.name = "Marvell 88E6185",
 		.num_ports = 10,
+		.num_internal_phys = 0,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6185_ops,
@@ -371,6 +485,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6190",
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_internal_phys = 11,
 		.port_base_addr = 0x0,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6190_ops,
@@ -381,6 +496,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6190X",
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_internal_phys = 11,
 		.port_base_addr = 0x0,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6190x_ops,
@@ -391,6 +507,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6191",
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_internal_phys = 11,
 		.port_base_addr = 0x0,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6191_ops,
@@ -401,6 +518,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6240",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6240_ops,
@@ -411,6 +529,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6290",
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_internal_phys = 11,
 		.port_base_addr = 0x0,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6290_ops,
@@ -421,6 +540,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6320,
 		.name = "Marvell 88E6320",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6320_ops,
@@ -431,6 +551,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6320,
 		.name = "Marvell 88E6321",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6321_ops,
@@ -441,6 +562,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6341,
 		.name = "Marvell 88E6341",
 		.num_ports = 6,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6341_ops,
@@ -451,6 +573,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6350",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6350_ops,
@@ -461,6 +584,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6351,
 		.name = "Marvell 88E6351",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6351_ops,
@@ -471,6 +595,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6352,
 		.name = "Marvell 88E6352",
 		.num_ports = 7,
+		.num_internal_phys = 5,
 		.port_base_addr = 0x10,
 		.ops = &mv88e6352_ops,
 		.global2_addr = 0x1c,
@@ -482,6 +607,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6390",
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_internal_phys = 11,
 		.port_base_addr = 0x0,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6390_ops,
@@ -492,6 +618,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
 		.family = MV88E6XXX_FAMILY_6390,
 		.name = "Marvell 88E6390X",
 		.num_ports = 11,	/* 10 + Z80 */
+		.num_internal_phys = 11,
 		.port_base_addr = 0x0,
 		.global2_addr = 0x1c,
 		.ops = &mv88e6390x_ops,
@@ -692,8 +819,8 @@ static int mv88e6xxx_probe(struct device_d *dev)
 	struct device_node *mdio_node;
 	struct mv88e6xxx_chip *chip;
 	enum of_gpio_flags of_flags;
-	int err;
 	u32 reg, eeprom_len = 0;
+	int err;
 
 	err = of_property_read_u32(np, "reg", &reg);
 	if (err) {
@@ -766,13 +893,16 @@ static int mv88e6xxx_probe(struct device_d *dev)
 	 * correspond to any PHYs, so we mask them to pervent from
 	 * being exposed as phy devices
 	 */
-	chip->parent_miibus->phy_mask |= GENMASK(0x1f, 0x10);
+	/* FIXME: This should probably use port_base_addr */
+
+	chip->parent_miibus->phy_mask |= GENMASK(0x1f,
+						 chip->info->port_base_addr);
 	/*
 	 * Address 0x0f on internal bus is dedicated to SERDES
 	 * registers and won't be very useful against standard PHY
 	 * driver
 	 */
-	chip->miibus.phy_mask |= GENMASK(0x1f, 0x0f);
+	chip->miibus.phy_mask |= GENMASK(0x1f, chip->info->num_ports);
 
 	chip->miibus.read = mv88e6xxx_mdio_read;
 	chip->miibus.write = mv88e6xxx_mdio_write;
@@ -784,7 +914,15 @@ static int mv88e6xxx_probe(struct device_d *dev)
 	if (mdio_node)
 		chip->miibus.dev.device_node = mdio_node;
 
-	return mdiobus_register(&chip->miibus);
+	err = m88e6xxx_port_probe(chip);
+	if (err)
+		return err;
+
+	err = mdiobus_register(&chip->miibus);
+	if (err)
+		return err;
+
+	return 0;
 }
 
 static const struct of_device_id mv88e6xxx_of_match[] = {
diff --git a/drivers/net/phy/mv88e6xxx/chip.h b/drivers/net/phy/mv88e6xxx/chip.h
index 021df2664..bc527efeb 100644
--- a/drivers/net/phy/mv88e6xxx/chip.h
+++ b/drivers/net/phy/mv88e6xxx/chip.h
@@ -26,23 +26,33 @@ enum mv88e6xxx_family {
 
 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 num_internal_phys;
 	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 {
@@ -50,6 +60,16 @@ struct ethtool_eeprom {
 	__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,
@@ -62,6 +82,58 @@ struct mv88e6xxx_ops {
 			  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);
diff --git a/drivers/net/phy/mv88e6xxx/port.c b/drivers/net/phy/mv88e6xxx/port.c
index 59afdbd97..c15b25cc2 100644
--- a/drivers/net/phy/mv88e6xxx/port.c
+++ b/drivers/net/phy/mv88e6xxx/port.c
@@ -1,6 +1,8 @@
 #include <common.h>
 #include <init.h>
 
+#include <linux/marvell_phy.h>
+
 #include "port.h"
 
 int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
@@ -18,3 +20,647 @@ int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
 
 	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)
+{
+	/* int lane; */
+	u16 cmode;
+	/* u16 reg; */
+	/* int err; */
+
+	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;
+	}
+#if 0
+	lane = mv88e6390x_serdes_get_lane(chip, port);
+	if (lane < 0)
+		return lane;
+
+	if (chip->ports[port].serdes_irq) {
+		err = mv88e6390_serdes_irq_disable(chip, port, lane);
+		if (err)
+			return err;
+	}
+
+	err = mv88e6390_serdes_power(chip, port, false);
+	if (err)
+		return err;
+
+	if (cmode) {
+		err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+		if (err)
+			return err;
+
+		reg &= ~MV88E6XXX_PORT_STS_CMODE_MASK;
+		reg |= cmode;
+
+		err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_STS, reg);
+		if (err)
+			return err;
+
+		err = mv88e6390_serdes_power(chip, port, true);
+		if (err)
+			return err;
+
+		if (chip->ports[port].serdes_irq) {
+			err = mv88e6390_serdes_irq_enable(chip, port, lane);
+			if (err)
+				return err;
+		}
+	}
+#endif
+	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 m88e6xxx_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 m88e6xxx_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;
+
+		err = mv88e6xxx_port_read(chip, i, MV88E6XXX_PORT_STS,
+					  &status);
+		if (err)
+			return err;
+
+		if (status & MV88E6XXX_PORT_STS_PHY_DETECT) {
+			/*
+			 * True PHYs will be automaticall handled by
+			 * generic PHY driver, so we ignore those.
+			 */
+			/* chip->parent_miibus->phy_mask &= ~BIT(i); */
+			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
index 84c76c42c..35fdc908d 100644
--- a/drivers/net/phy/mv88e6xxx/port.h
+++ b/drivers/net/phy/mv88e6xxx/port.h
@@ -15,6 +15,7 @@
 #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
@@ -27,14 +28,28 @@
 #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 MV88E6185_PORT_STS_CMODE_1000BASE_X	0x0005
+#define MV88E6185_PORT_STS_CMODE_PHY		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
@@ -85,5 +100,28 @@ int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
 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 m88e6xxx_port_probe(struct mv88e6xxx_chip *chip);
+
 
 #endif /* _MV88E6XXX_PORT_H */
\ No newline at end of file
-- 
2.17.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 02/16] clocksource: Add ARM global timer support
  2018-10-08  6:35 ` [PATCH 02/16] clocksource: Add ARM global timer support Andrey Smirnov
@ 2018-10-08  8:17   ` Sascha Hauer
  2018-10-08 15:37     ` Andrey Smirnov
  0 siblings, 1 reply; 24+ messages in thread
From: Sascha Hauer @ 2018-10-08  8:17 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Sun, Oct 07, 2018 at 11:35:28PM -0700, Andrey Smirnov wrote:
> Port corresponding Linux kernel driver. Currently VFxxx SoC is the
> intended consumer because it doesn't include common i.MX GPT block
> used as clocksource by other i.MX SoCs.
> 
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  drivers/clocksource/Kconfig            |   4 +
>  drivers/clocksource/Makefile           |   1 +
>  drivers/clocksource/arm_global_timer.c | 113 +++++++++++++++++++++++++
>  3 files changed, 118 insertions(+)
>  create mode 100644 drivers/clocksource/arm_global_timer.c
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 3d63f7ff1..2be5a76b3 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -70,3 +70,7 @@ config CLOCKSOURCE_ARMV8_TIMER
>  	bool
>  	default y
>  	depends on ARM && CPU_64v8
> +
> +config CLOCKSOURCE_ARM_GLOBAL_TIMER
> +        def_bool y
> +	depends on ARM

Can you add a 'select' of this option to the VFxxx Kconfig instead?
Having this on all Arm systems is not so nice.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 13/16] mdio_bus: Allow for non PHY-devices on MDIO buses
  2018-10-08  6:35 ` [PATCH 13/16] mdio_bus: Allow for non PHY-devices on MDIO buses Andrey Smirnov
@ 2018-10-08  8:44   ` Sascha Hauer
  2018-10-08 15:41     ` Andrey Smirnov
  0 siblings, 1 reply; 24+ messages in thread
From: Sascha Hauer @ 2018-10-08  8:44 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Sun, Oct 07, 2018 at 11:35:39PM -0700, Andrey Smirnov wrote:
> Instead of just creating a simple PHY device for every child of MDIO
> bus node, add code to check if any of them have "compatible" property
> set as well as code to create a proper platform device for such cases.
> 
> This change is useful for when MDIO bus and some of Ethernet ports are
> connected to a switch or some other MDIO device that doesn't behave
> like a generic PHY and can't be probed via its PHY ID.
> 
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  drivers/net/phy/mdio_bus.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
> index d7d6d8940..589ed57d2 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,6 +180,16 @@ 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_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;
> +		}

PHYs can have a compatible property aswell which is checked for here:

> +
>  		if (!of_mdiobus_child_is_phy(child))
>  			continue;

So I believe you have to create a platform device only if it is not a
PHY device.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 02/16] clocksource: Add ARM global timer support
  2018-10-08  8:17   ` Sascha Hauer
@ 2018-10-08 15:37     ` Andrey Smirnov
  0 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08 15:37 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

On Mon, Oct 8, 2018 at 1:17 AM Sascha Hauer <s.hauer@pengutronix.de> wrote:
>
> On Sun, Oct 07, 2018 at 11:35:28PM -0700, Andrey Smirnov wrote:
> > Port corresponding Linux kernel driver. Currently VFxxx SoC is the
> > intended consumer because it doesn't include common i.MX GPT block
> > used as clocksource by other i.MX SoCs.
> >
> > Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> > ---
> >  drivers/clocksource/Kconfig            |   4 +
> >  drivers/clocksource/Makefile           |   1 +
> >  drivers/clocksource/arm_global_timer.c | 113 +++++++++++++++++++++++++
> >  3 files changed, 118 insertions(+)
> >  create mode 100644 drivers/clocksource/arm_global_timer.c
> >
> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> > index 3d63f7ff1..2be5a76b3 100644
> > --- a/drivers/clocksource/Kconfig
> > +++ b/drivers/clocksource/Kconfig
> > @@ -70,3 +70,7 @@ config CLOCKSOURCE_ARMV8_TIMER
> >       bool
> >       default y
> >       depends on ARM && CPU_64v8
> > +
> > +config CLOCKSOURCE_ARM_GLOBAL_TIMER
> > +        def_bool y
> > +     depends on ARM
>
> Can you add a 'select' of this option to the VFxxx Kconfig instead?
> Having this on all Arm systems is not so nice.
>

Sure, no problem, will do in v2.

Thanks,
Andrey Smirnov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 13/16] mdio_bus: Allow for non PHY-devices on MDIO buses
  2018-10-08  8:44   ` Sascha Hauer
@ 2018-10-08 15:41     ` Andrey Smirnov
  0 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-08 15:41 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

On Mon, Oct 8, 2018 at 1:44 AM Sascha Hauer <s.hauer@pengutronix.de> wrote:
>
> On Sun, Oct 07, 2018 at 11:35:39PM -0700, Andrey Smirnov wrote:
> > Instead of just creating a simple PHY device for every child of MDIO
> > bus node, add code to check if any of them have "compatible" property
> > set as well as code to create a proper platform device for such cases.
> >
> > This change is useful for when MDIO bus and some of Ethernet ports are
> > connected to a switch or some other MDIO device that doesn't behave
> > like a generic PHY and can't be probed via its PHY ID.
> >
> > Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> > ---
> >  drivers/net/phy/mdio_bus.c | 11 +++++++++++
> >  1 file changed, 11 insertions(+)
> >
> > diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
> > index d7d6d8940..589ed57d2 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,6 +180,16 @@ 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_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;
> > +             }
>
> PHYs can have a compatible property aswell which is checked for here:
>
> > +
> >               if (!of_mdiobus_child_is_phy(child))
> >                       continue;
>
> So I believe you have to create a platform device only if it is not a
> PHY device.
>

Yeah, good point, missed this in my logic. Will fix in v2.

Thanks,
Andrey Smirnov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 06/16] drivers: Introduce dev_set_name()
  2018-10-08  6:35 ` [PATCH 06/16] drivers: Introduce dev_set_name() Andrey Smirnov
@ 2018-10-09 15:41   ` Sam Ravnborg
  2018-10-09 17:10     ` Andrey Smirnov
  0 siblings, 1 reply; 24+ messages in thread
From: Sam Ravnborg @ 2018-10-09 15:41 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

Hi Andrey.

Looked through the patch, everythign looked OK.
One nit.

	Sam

> diff --git a/include/driver.h b/include/driver.h
> index 1b61f2066..7b83c0a77 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>
> @@ -41,7 +40,7 @@ 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. */
Add here: The name is set using dev_set_name() or somthing like that.
To let the reader/user know how to set the name in the correct way.

> -	char name[MAX_DRIVER_NAME];
> +	char *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. */
> @@ -177,6 +176,8 @@ 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, ...);
> +
It would be nice with a small comment that tell this is used to set
device_d.name - and that it shuld not be assigned direct.


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 06/16] drivers: Introduce dev_set_name()
  2018-10-09 15:41   ` Sam Ravnborg
@ 2018-10-09 17:10     ` Andrey Smirnov
  0 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-09 17:10 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: Barebox List

On Tue, Oct 9, 2018 at 8:41 AM Sam Ravnborg <sam@ravnborg.org> wrote:
>
> Hi Andrey.
>
> Looked through the patch, everythign looked OK.
> One nit.
>
>         Sam
>
> > diff --git a/include/driver.h b/include/driver.h
> > index 1b61f2066..7b83c0a77 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>
> > @@ -41,7 +40,7 @@ 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. */
> Add here: The name is set using dev_set_name() or somthing like that.
> To let the reader/user know how to set the name in the correct way.
>

I'll add a mention of it in the documentation, but strictly speaking
dev_set_name() is not mandatory to use. Driver can choose to assign
constant strings to that field and it wouldn't be unreasonable.

> > -     char name[MAX_DRIVER_NAME];
> > +     char *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. */
> > @@ -177,6 +176,8 @@ 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, ...);
> > +
> It would be nice with a small comment that tell this is used to set
> device_d.name - and that it shuld not be assigned direct.
>

Same here, device_d.name can be assigned directly. However
dev_set_name() does assume that device_d.name is free()-able, so I'll
mention that in the comment.

Will update both in v2.

Thanks,
Andrey Smirnov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/16]
  2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
                   ` (15 preceding siblings ...)
  2018-10-08  6:35 ` [PATCH 16/16] net: phy: mv88e6xxx: Add support for MAC ports Andrey Smirnov
@ 2018-10-09 17:30 ` Andrey Smirnov
  16 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-09 17:30 UTC (permalink / raw)
  To: Barebox List

On Sun, Oct 7, 2018 at 11:35 PM Andrey Smirnov <andrew.smirnov@gmail.com> wrote:
>
> Everyone:
>
> Patches in this series are a result of my work on porting Linux code
> for MV88E6xxx switches to Barebox.
>
>      - Patch 1 is loosely related header fix
>
>      - Patch 2 adds clocksource support for ARM global time, needed on
>        VF610 in order to get an accurate clocksource. MV88E6xxx EEPROM
>        supporte code turned out to be dependent on that.
>
>      - Pathes 3 and 4 are clocksource related fixes
>
>      - Patches 5, 6, 7, 8 update the device naming scheme used by
>        Barebox driver code. Old scheme couldn't handle devices created
>        for DT nodes with identical names. This was the case on ZII
>        VF610 Development Board Rev. C which had two switch devices.
>
>     - Patch 9 is documentation/small code fix for generic MDIO bus
>       code
>
>     - Patches 10, 11 bring needed preprocessor constants from Linux kernel
>
>     - Patch 12 prevents PHYs masked by MDIO bus's phy_maks from being
>       probed
>
>     - Patch 13 allows custom platform deviecs to be attached to an MDIO bus
>
>     - Patch 14 exposes internal MDIO bus on MV88E6xxx devices
>
>     - Patch 15 support for EEPROM devices attached to MV88E6xxx devices
>
>     - Patch 16 exposes ports that don't have a PHY attached as
>       "virtual" PHY devices (RPU2 needs this code to properly
>       configure port connected to FEC)
>
> NOTE: This is quite a mix and I am more than happy to split this
> series in several if current patch grouping is problematic.
>
> Tested on the following H/W:
>
>      - ZII i.MX6Q RDU2, MV88E6352 switch
>      - ZII i.MX51 RDU1, MV88E6161 switch
>      - ZII i.MX7D RPU2, MV88E6352 switch
>      - ZII VF610 CFU1, MV88E6352 switch
>      - ZII VF610 SPU3, MV88E6390X switch
>      - ZII VF610 Development Board Rev. C, MV88E6390X switch x 2
>
> Feedback is welcome!
>
> Thanks,
> Andrey Smirnov
>

This is really embarrassing that I forgot to have an actual subject
line for this series. Will fix in v2.

Thanks,
Andrey Smirnov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2018-10-09 17:30 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-08  6:35 [PATCH 00/16] Andrey Smirnov
2018-10-08  6:35 ` [PATCH 01/16] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
2018-10-08  6:35 ` [PATCH 02/16] clocksource: Add ARM global timer support Andrey Smirnov
2018-10-08  8:17   ` Sascha Hauer
2018-10-08 15:37     ` Andrey Smirnov
2018-10-08  6:35 ` [PATCH 03/16] i.MX: Move GPT driver to drivers/clocksource Andrey Smirnov
2018-10-08  6:35 ` [PATCH 04/16] clocksource: Introduce ARCH_HAS_IMX_GPT Andrey Smirnov
2018-10-08  6:35 ` [PATCH 05/16] of: Demote "Bad cell count for" to debug Andrey Smirnov
2018-10-08  6:35 ` [PATCH 06/16] drivers: Introduce dev_set_name() Andrey Smirnov
2018-10-09 15:41   ` Sam Ravnborg
2018-10-09 17:10     ` Andrey Smirnov
2018-10-08  6:35 ` [PATCH 07/16] linux: string: Port kbasename() Andrey Smirnov
2018-10-08  6:35 ` [PATCH 08/16] of: Port latest of_device_make_bus_id() implementation Andrey Smirnov
2018-10-08  6:35 ` [PATCH 09/16] mdio_bus: Fix documentation for mdio_bus_match() Andrey Smirnov
2018-10-08  6:35 ` [PATCH 10/16] include: linux: phy: Add missing PHY_INTERFACE_* constants Andrey Smirnov
2018-10-08  6:35 ` [PATCH 11/16] include: linux: ethtool: Add missing *_UNKNOWN constants Andrey Smirnov
2018-10-08  6:35 ` [PATCH 12/16] net: phy: Check phy_mask in get_phy_device() Andrey Smirnov
2018-10-08  6:35 ` [PATCH 13/16] mdio_bus: Allow for non PHY-devices on MDIO buses Andrey Smirnov
2018-10-08  8:44   ` Sascha Hauer
2018-10-08 15:41     ` Andrey Smirnov
2018-10-08  6:35 ` [PATCH 14/16] net: phy: Add basic driver for MV88E6XXX switches from Marvell Andrey Smirnov
2018-10-08  6:35 ` [PATCH 15/16] net: phy: mv88e6xxx: Port EEPROM support code Andrey Smirnov
2018-10-08  6:35 ` [PATCH 16/16] net: phy: mv88e6xxx: Add support for MAC ports Andrey Smirnov
2018-10-09 17:30 ` [PATCH 00/16] Andrey Smirnov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox