mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v4 00/22] MV88E6xxx switch family support
@ 2018-10-16 19:15 Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 01/22] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
                   ` (22 more replies)
  0 siblings, 23 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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.

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!

Changes since [v3]:

   - Fix spaces/tabs mixup, missing newlines

Changes since [v2]:

   - Added code to deal with port layout on MV88E6161

   - Removed unused, #ifdefed-out code

   - basename() re-implemented using kbasename()

   - Added patches to deal with device name collision in aiodev
     reported by Lucas

   - Patch introducing dev_set_name() was split in two

   - Added fix for dev_id()'s global buffer "collision"

   - Removed a patch hunk for code that's not yet in "next"

Changes since [v1]:

    - CONFIG_CLOCKSOURCE_ARM_GLOBAL_TIMER is not selected by
      default. VF610 now selects it explicitly

    - Incorrect logic in patch 14/17 was fixed to correctly handle PHY
      nodes that have "compatible" property

    - Added more documentation for dev_set_name()

[v3] http://lists.infradead.org/pipermail/barebox/2018-October/035015.html
[v2] http://lists.infradead.org/pipermail/barebox/2018-October/034965.html
[v1] http://lists.infradead.org/pipermail/barebox/2018-October/034963.html

Andrey Smirnov (22):
  ARM: Do not expose ARMv8 functions on ARMv7
  clocksource: Add ARM global timer support
  VFxxx: Select CLOCKSOURCE_ARM_GLOBAL_TIMER
  i.MX: Move GPT driver to drivers/clocksource
  clocksource: Introduce ARCH_HAS_IMX_GPT
  of: Demote "Bad cell count for" to debug
  aiodev: Don't try to use DT node name as aiodev->name
  aiodev: imx_thermal: Give aiodev a more descriptive name
  aiodev: qoriq_thermal: Give aiodev a more descriptive name
  drivers: Introduce dev_set_name()
  base: Don't use shared buffer for results of dev_id()
  drivers: base: Convert device_d name to be dynamically allocated
  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                     |  12 +
 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                         |   4 +-
 drivers/aiodev/imx_thermal.c                  |   1 +
 drivers/aiodev/qoriq_thermal.c                |   1 +
 drivers/amba/bus.c                            |   2 +-
 drivers/ata/disk_ata_drive.c                  |   4 +-
 drivers/base/bus.c                            |   2 +-
 drivers/base/driver.c                         |  45 +-
 drivers/base/resource.c                       |   2 +-
 drivers/clocksource/Kconfig                   |  10 +
 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/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                    |  27 +-
 drivers/net/phy/mv88e6xxx/Makefile            |   5 +
 drivers/net/phy/mv88e6xxx/chip.c              | 913 ++++++++++++++++++
 drivers/net/phy/mv88e6xxx/chip.h              | 142 +++
 drivers/net/phy/mv88e6xxx/global2.c           | 389 ++++++++
 drivers/net/phy/mv88e6xxx/global2.h           |  70 ++
 drivers/net/phy/mv88e6xxx/port.c              | 663 +++++++++++++
 drivers/net/phy/mv88e6xxx/port.h              | 137 +++
 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                              |  25 +-
 include/linux/ethtool.h                       |   3 +
 include/linux/phy.h                           |   9 +
 include/linux/string.h                        |  12 +
 lib/libgen.c                                  |  16 +-
 net/eth.c                                     |   2 +-
 68 files changed, 2649 insertions(+), 155 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 v4 01/22] ARM: Do not expose ARMv8 functions on ARMv7
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 02/22] clocksource: Add ARM global timer support Andrey Smirnov
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 v4 02/22] clocksource: Add ARM global timer support
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 01/22] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 03/22] VFxxx: Select CLOCKSOURCE_ARM_GLOBAL_TIMER Andrey Smirnov
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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..ec1e622b4 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
+	bool
+	depends on ARM && CPU_V7
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 v4 03/22] VFxxx: Select CLOCKSOURCE_ARM_GLOBAL_TIMER
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 01/22] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 02/22] clocksource: Add ARM global timer support Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 04/22] i.MX: Move GPT driver to drivers/clocksource Andrey Smirnov
                   ` (19 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-imx/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 4a56fb9f4..8d161bee2 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -185,6 +185,7 @@ config ARCH_VF610
 	select COMMON_CLK_OF_PROVIDER
 	select NVMEM
 	select IMX_OCOTP	# Needed for clock adjustement
+	select CLOCKSOURCE_ARM_GLOBAL_TIMER
 
 config IMX_MULTI_BOARDS
 	bool "Allow multiple boards to be selected"
-- 
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 v4 04/22] i.MX: Move GPT driver to drivers/clocksource
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (2 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 03/22] VFxxx: Select CLOCKSOURCE_ARM_GLOBAL_TIMER Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 05/22] clocksource: Introduce ARCH_HAS_IMX_GPT Andrey Smirnov
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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                                    | 3 +++
 drivers/clocksource/Makefile                                   | 1 +
 .../clocksource.c => drivers/clocksource/timer-imx-gpt.c       | 0
 4 files changed, 4 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 ec1e622b4..1a33b2f0c 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -74,3 +74,6 @@ config CLOCKSOURCE_ARMV8_TIMER
 config CLOCKSOURCE_ARM_GLOBAL_TIMER
 	bool
 	depends on ARM && CPU_V7
+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 v4 05/22] clocksource: Introduce ARCH_HAS_IMX_GPT
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (3 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 04/22] i.MX: Move GPT driver to drivers/clocksource Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 06/22] of: Demote "Bad cell count for" to debug Andrey Smirnov
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 8d161bee2..3aff62d89 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 1a33b2f0c..3caf72503 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
@@ -76,4 +79,4 @@ config CLOCKSOURCE_ARM_GLOBAL_TIMER
 	depends on ARM && CPU_V7
 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 v4 06/22] of: Demote "Bad cell count for" to debug
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (4 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 05/22] clocksource: Introduce ARCH_HAS_IMX_GPT Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 07/22] aiodev: Don't try to use DT node name as aiodev->name Andrey Smirnov
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 v4 07/22] aiodev: Don't try to use DT node name as aiodev->name
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (5 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 06/22] of: Demote "Bad cell count for" to debug Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 08/22] aiodev: imx_thermal: Give aiodev a more descriptive name Andrey Smirnov
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Don't try to use DT node name as aiodev->name in aiodev_regster()
since, for some devices (e. g. tempmon) than name would already be
taken by parent platform device.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/aiodev/core.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/aiodev/core.c b/drivers/aiodev/core.c
index 79f935d71..90df8a6e7 100644
--- a/drivers/aiodev/core.c
+++ b/drivers/aiodev/core.c
@@ -106,8 +106,6 @@ int aiodevice_register(struct aiodevice *aiodev)
 		aiodev->dev.id = DEVICE_ID_SINGLE;
 
 		aiodev->name = of_alias_get(aiodev->hwdev->device_node);
-		if (!aiodev->name)
-			aiodev->name = aiodev->hwdev->device_node->name;
 	}
 
 	if (!aiodev->name) {
-- 
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 v4 08/22] aiodev: imx_thermal: Give aiodev a more descriptive name
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (6 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 07/22] aiodev: Don't try to use DT node name as aiodev->name Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 09/22] aiodev: qoriq_thermal: " Andrey Smirnov
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/aiodev/imx_thermal.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/aiodev/imx_thermal.c b/drivers/aiodev/imx_thermal.c
index c020a1091..9e5070835 100644
--- a/drivers/aiodev/imx_thermal.c
+++ b/drivers/aiodev/imx_thermal.c
@@ -177,6 +177,7 @@ static int imx_thermal_probe(struct device_d *dev)
 
 	imx_thermal->aiodev.num_channels = 1;
 	imx_thermal->aiodev.hwdev = dev;
+	imx_thermal->aiodev.name = "thermal-sensor";
 	imx_thermal->aiodev.channels =
 		xmalloc(imx_thermal->aiodev.num_channels *
 			sizeof(imx_thermal->aiodev.channels[0]));
-- 
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 v4 09/22] aiodev: qoriq_thermal: Give aiodev a more descriptive name
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (7 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 08/22] aiodev: imx_thermal: Give aiodev a more descriptive name Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 10/22] drivers: Introduce dev_set_name() Andrey Smirnov
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/aiodev/qoriq_thermal.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/aiodev/qoriq_thermal.c b/drivers/aiodev/qoriq_thermal.c
index d29da02a6..7556fef02 100644
--- a/drivers/aiodev/qoriq_thermal.c
+++ b/drivers/aiodev/qoriq_thermal.c
@@ -232,6 +232,7 @@ static int qoriq_tmu_probe(struct device_d *dev)
 
 	data->aiodev.num_channels = 1;
 	data->aiodev.hwdev = dev;
+	data->aiodev.name = "thermal-sensor";
 	data->aiodev.channels = xmalloc(data->aiodev.num_channels *
 					sizeof(data->aiodev.channels[0]));
 	data->aiodev.channels[0] = &data->aiochan;
-- 
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 v4 10/22] drivers: Introduce dev_set_name()
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (8 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 09/22] aiodev: qoriq_thermal: " Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 11/22] base: Don't use shared buffer for results of dev_id() Andrey Smirnov
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Introduce dev_set_name() in order to hide implementation details of
setting device's name so it'd be easier to change 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                         | 21 +++++++++++++++++++
 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/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                              | 11 +++++++---
 net/eth.c                                     |  2 +-
 45 files changed, 89 insertions(+), 63 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 90df8a6e7..b5d06da93 100644
--- a/drivers/aiodev/core.c
+++ b/drivers/aiodev/core.c
@@ -113,7 +113,7 @@ int aiodevice_register(struct aiodevice *aiodev)
 		aiodev->dev.id = DEVICE_ID_DYNAMIC;
 	}
 
-	strcpy(aiodev->dev.name, aiodev->name);
+	dev_set_name(&aiodev->dev, aiodev->name);
 
 	aiodev->dev.parent = aiodev->hwdev;
 
diff --git a/drivers/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..c9e6e6ddd 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -478,6 +478,27 @@ const char *dev_id(const struct device_d *dev)
 	return buf;
 }
 
+/**
+ * dev_set_name - set a device name
+ * @dev: device
+ * @fmt: format string for the device's name
+ *
+ */
+int dev_set_name(struct device_d *dev, const char *fmt, ...)
+{
+	va_list vargs;
+	int err;
+
+	va_start(vargs, fmt);
+	err = vsnprintf(dev->name, sizeof(dev->name), fmt, vargs);
+	va_end(vargs);
+
+	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/mtd/core.c b/drivers/mtd/core.c
index 15fe9ce79..56e85b3d8 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -607,7 +607,7 @@ int add_mtd_device(struct mtd_info *mtd, const char *devname, int device_id)
 
 	if (!devname)
 		devname = "mtd";
-	strcpy(mtd->class_dev.name, devname);
+	dev_set_name(&mtd->class_dev, devname);
 	mtd->class_dev.id = device_id;
 	if (mtd->parent)
 		mtd->class_dev.parent = mtd->parent;
diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c
index 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 d76d82914..57eaaf585 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2757,7 +2757,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..c12ca9c2f 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -38,9 +38,12 @@ struct platform_device_id {
 
 /** @brief Describes a particular device present in the system */
 struct device_d {
-	/*! This member (and 'type' described below) is used to match with a
-	 * driver. This is a descriptive name and could be MPC5XXX_ether or
-	 * imx_serial. */
+	/*! This member (and 'type' described below) is used to match
+	 * with a driver. This is a descriptive name and could be
+	 * MPC5XXX_ether or imx_serial. Unless absolutely necessary,
+	 * should not be modified directly and dev_set_name() should
+	 * be used instead.
+	 */
 	char name[MAX_DRIVER_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
@@ -177,6 +180,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 v4 11/22] base: Don't use shared buffer for results of dev_id()
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (9 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 10/22] drivers: Introduce dev_set_name() Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 12/22] drivers: base: Convert device_d name to be dynamically allocated Andrey Smirnov
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Using shared memory buffer to return results of dev_id() leads to
incorrect results when used as follows:

    dev_info(..., "... %s ...\n", ..., dev_name(foo), ...);

since result returned for dev_name(foo) will be overwritten by
dev_name() call that will happen as a part of dev_* logging functions.

To prevent that allocate a dedicated field "unique_name" in struct
device_d and use it to store unique name returned by
dev_id()/dev_name().

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/base/driver.c | 19 +++++++------------
 include/driver.h      | 11 ++++++++++-
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index c9e6e6ddd..b7720f31a 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -183,6 +183,13 @@ int register_device(struct device_d *new_device)
 		}
 	}
 
+	if (new_device->id != DEVICE_ID_SINGLE)
+		snprintf(new_device->unique_name,
+			 sizeof(new_device->unique_name),
+			 FORMAT_DRIVER_NAME_ID,
+			 new_device->name,
+			 new_device->id);
+
 	debug ("register_device: %s\n", dev_name(new_device));
 
 	list_add_tail(&new_device->list, &device_list);
@@ -466,18 +473,6 @@ int dummy_probe(struct device_d *dev)
 }
 EXPORT_SYMBOL(dummy_probe);
 
-const char *dev_id(const struct device_d *dev)
-{
-	static char buf[MAX_DRIVER_NAME + 16];
-
-	if (dev->id != DEVICE_ID_SINGLE)
-		snprintf(buf, sizeof(buf), FORMAT_DRIVER_NAME_ID, dev->name, dev->id);
-	else
-		snprintf(buf, sizeof(buf), "%s", dev->name);
-
-	return buf;
-}
-
 /**
  * dev_set_name - set a device name
  * @dev: device
diff --git a/include/driver.h b/include/driver.h
index c12ca9c2f..94fddc735 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -45,6 +45,12 @@ struct device_d {
 	 * be used instead.
 	 */
 	char name[MAX_DRIVER_NAME];
+
+	/*! This member is used to store device's unique name as
+	 *  obtained by calling dev_id(). Internal field, do not
+	 *  access it directly.
+	  */
+	char unique_name[MAX_DRIVER_NAME + 16];
 	/*! 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. */
@@ -173,7 +179,10 @@ int get_free_deviceid(const char *name_template);
 
 char *deviceid_from_spec_str(const char *str, char **endp);
 
-extern const char *dev_id(const struct device_d *dev);
+static inline const char *dev_id(const struct device_d *dev)
+{
+	return (dev->id != DEVICE_ID_SINGLE) ? dev->unique_name : dev->name;
+}
 
 static inline const char *dev_name(const struct device_d *dev)
 {
-- 
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 v4 12/22] drivers: base: Convert device_d name to be dynamically allocated
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (10 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 11/22] base: Don't use shared buffer for results of dev_id() Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 13/22] linux: string: Port kbasename() Andrey Smirnov
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Convert device_d name to be dynamically allocated in order to lift
MAX_DRIVER_NAME length limit needed for commits that follow.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/base/driver.c | 23 +++++++++++++++++------
 include/driver.h      |  5 ++---
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index b7720f31a..1941a972c 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -184,11 +184,9 @@ int register_device(struct device_d *new_device)
 	}
 
 	if (new_device->id != DEVICE_ID_SINGLE)
-		snprintf(new_device->unique_name,
-			 sizeof(new_device->unique_name),
-			 FORMAT_DRIVER_NAME_ID,
-			 new_device->name,
-			 new_device->id);
+		new_device->unique_name = basprintf(FORMAT_DRIVER_NAME_ID,
+						    new_device->name,
+						    new_device->id);
 
 	debug ("register_device: %s\n", dev_name(new_device));
 
@@ -478,16 +476,29 @@ EXPORT_SYMBOL(dummy_probe);
  * @dev: device
  * @fmt: format string for the device's name
  *
+ * NOTE: This function expects dev->name to be free()-able, so extra
+ * precautions needs to be taken when mixing its usage with manual
+ * assignement of device_d.name.
  */
 int dev_set_name(struct device_d *dev, const char *fmt, ...)
 {
 	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 = vsnprintf(dev->name, sizeof(dev->name), fmt, vargs);
+	err = vasprintf(&dev->name, fmt, vargs);
 	va_end(vargs);
 
+	/*
+	 * Free old pointer, we do this after vasprintf call in case
+	 * old device name was in one of vargs
+	 */
+	free(oldname);
+
 	WARN_ON(err < 0);
 
 	return err;
diff --git a/include/driver.h b/include/driver.h
index 94fddc735..db844aed3 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>
@@ -44,13 +43,13 @@ struct device_d {
 	 * should not be modified directly and dev_set_name() should
 	 * be used instead.
 	 */
-	char name[MAX_DRIVER_NAME];
+	char *name;
 
 	/*! This member is used to store device's unique name as
 	 *  obtained by calling dev_id(). Internal field, do not
 	 *  access it directly.
 	  */
-	char unique_name[MAX_DRIVER_NAME + 16];
+	char *unique_name;
 	/*! The id is used to uniquely identify a device in the system. The id
 	 * will show up under /dev/ as the device's name. Usually this is
 	 * something like eth0 or nor0. */
-- 
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 v4 13/22] linux: string: Port kbasename()
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (11 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 12/22] drivers: base: Convert device_d name to be dynamically allocated Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 14/22] of: Port latest of_device_make_bus_id() implementation Andrey Smirnov
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port kbasename() from Linux and use it to implement basename() we
already have.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 include/linux/string.h | 12 ++++++++++++
 lib/libgen.c           | 16 ++--------------
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/include/linux/string.h b/include/linux/string.h
index 3418b4fbe..c9823dab8 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -111,6 +111,18 @@ extern char *strim(char *);
 
 void *memchr_inv(const void *start, int c, size_t bytes);
 
+/**
+ * kbasename - return the last part of a pathname.
+ *
+ * @path: path to extract the filename from.
+ */
+static inline const char *kbasename(const char *path)
+{
+	const char *tail = strrchr(path, '/');
+	return tail ? tail + 1 : path;
+}
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/libgen.c b/lib/libgen.c
index 08ef3528a..61a8670fb 100644
--- a/lib/libgen.c
+++ b/lib/libgen.c
@@ -17,23 +17,11 @@
 
 #include <common.h>
 #include <libgen.h>
+#include <linux/string.h>
 
 char *basename (char *path)
 {
-	char *fname;
-
-	if(!strchr(path, '/'))
-		return path;
-
-	fname = path + strlen(path) - 1;
-	while (fname >= path) {
-		if (*fname == '/') {
-			fname++;
-			break;
-		}
-		fname--;
-	}
-	return fname;
+	return (char *)kbasename(path);
 }
 EXPORT_SYMBOL(basename);
 
-- 
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 v4 14/22] of: Port latest of_device_make_bus_id() implementation
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (12 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 13/22] linux: string: Port kbasename() Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 15/22] mdio_bus: Fix documentation for mdio_bus_match() Andrey Smirnov
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 v4 15/22] mdio_bus: Fix documentation for mdio_bus_match()
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (13 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 14/22] of: Port latest of_device_make_bus_id() implementation Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 16/22] include: linux: phy: Add missing PHY_INTERFACE_* constants Andrey Smirnov
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 v4 16/22] include: linux: phy: Add missing PHY_INTERFACE_* constants
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (14 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 15/22] mdio_bus: Fix documentation for mdio_bus_match() Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 17/22] include: linux: ethtool: Add missing *_UNKNOWN constants Andrey Smirnov
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 v4 17/22] include: linux: ethtool: Add missing *_UNKNOWN constants
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (15 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 16/22] include: linux: phy: Add missing PHY_INTERFACE_* constants Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 18/22] net: phy: Check phy_mask in get_phy_device() Andrey Smirnov
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 v4 18/22] net: phy: Check phy_mask in get_phy_device()
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (16 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 17/22] include: linux: ethtool: Add missing *_UNKNOWN constants Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 19/22] mdio_bus: Allow for non PHY-devices on MDIO buses Andrey Smirnov
                   ` (4 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Do not try to probe PHY devices if they are masked in phy_mask. This
way we won't try adding devices that are unlikely to be proper PHYs by
default. With this change it still remains possible to add such a
device 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 v4 19/22] mdio_bus: Allow for non PHY-devices on MDIO buses
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (17 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 18/22] net: phy: Check phy_mask in get_phy_device() Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 20/22] net: phy: Add basic driver for MV88E6XXX switches from Marvell Andrey Smirnov
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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 | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index d7d6d8940..cda05afae 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <linux/phy.h>
 #include <linux/err.h>
+#include <of_device.h>
 
 #define DEFAULT_GPIO_RESET_ASSERT       1000      /* us */
 #define DEFAULT_GPIO_RESET_DEASSERT     1000      /* us */
@@ -179,8 +180,19 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
 
 	/* Loop over the child nodes and register a phy_device for each one */
 	for_each_available_child_of_node(np, child) {
-		if (!of_mdiobus_child_is_phy(child))
+		if (!of_mdiobus_child_is_phy(child)) {
+			if (of_get_property(child, "compatible", NULL)) {
+				if (!of_platform_device_create(child,
+							       &mdio->dev)) {
+					dev_err(&mdio->dev,
+						"Failed to create device "
+						"for %s\n",
+						child->full_name);
+				}
+			}
+
 			continue;
+		}
 
 		ret = of_property_read_u32(child, "reg", &addr);
 		if (ret) {
-- 
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 v4 20/22] net: phy: Add basic driver for MV88E6XXX switches from Marvell
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (18 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 19/22] mdio_bus: Allow for non PHY-devices on MDIO buses Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 21/22] net: phy: mv88e6xxx: Port EEPROM support code Andrey Smirnov
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 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>
---
 drivers/net/phy/Kconfig             |   6 +
 drivers/net/phy/Makefile            |   1 +
 drivers/net/phy/mv88e6xxx/Makefile  |   5 +
 drivers/net/phy/mv88e6xxx/chip.c    | 723 ++++++++++++++++++++++++++++
 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, 1070 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..e09ea0aa4
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/Makefile
@@ -0,0 +1,5 @@
+obj-y += mv88e6xxx.o
+
+mv88e6xxx-objs := chip.o
+mv88e6xxx-objs += global2.o
+mv88e6xxx-objs += port.o
diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
new file mode 100644
index 000000000..cc4bfc02e
--- /dev/null
+++ b/drivers/net/phy/mv88e6xxx/chip.c
@@ -0,0 +1,723 @@
+#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"
+
+
+/* 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..6c3f0705b
--- /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 */
diff --git a/drivers/net/phy/mv88e6xxx/global2.c b/drivers/net/phy/mv88e6xxx/global2.c
new file mode 100644
index 000000000..a3c7bc0e5
--- /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..0d8e9f359
--- /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 */
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..7bb2e8bb4
--- /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 */
-- 
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 v4 21/22] net: phy: mv88e6xxx: Port EEPROM support code
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (19 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 20/22] net: phy: Add basic driver for MV88E6XXX switches from Marvell Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-16 19:15 ` [PATCH v4 22/22] net: phy: mv88e6xxx: Add support for MAC ports Andrey Smirnov
  2018-10-18  7:02 ` [PATCH v4 00/22] MV88E6xxx switch family support Sascha Hauer
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/phy/mv88e6xxx/chip.c    |  84 +++++++++
 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(+)

diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
index cc4bfc02e..7eb961fc0 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>
@@ -79,6 +80,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,
 };
@@ -104,6 +107,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,
 };
@@ -116,6 +121,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,
 };
@@ -129,48 +136,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,
 };
@@ -191,16 +214,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,
 };
@@ -621,12 +650,48 @@ 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;
 	struct device_node *mdio_node;
 	struct mv88e6xxx_chip *chip;
 	enum of_gpio_flags of_flags;
+	u32 eeprom_len = 0;
 	int err;
 	u32 reg;
 
@@ -643,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;
@@ -676,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 6c3f0705b..3a798a11e 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 a3c7bc0e5..970a7291e 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 0d8e9f359..4e23b0423 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 */
-- 
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 v4 22/22] net: phy: mv88e6xxx: Add support for MAC ports
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (20 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 21/22] net: phy: mv88e6xxx: Port EEPROM support code Andrey Smirnov
@ 2018-10-16 19:15 ` Andrey Smirnov
  2018-10-18  7:02 ` [PATCH v4 00/22] MV88E6xxx switch family support Sascha Hauer
  22 siblings, 0 replies; 24+ messages in thread
From: Andrey Smirnov @ 2018-10-16 19:15 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Add support for MAC-only/no-PHY ports by adding code that will create
a pseudo PHY device for such ports and a driver to match
against. Original Linux driver exposes all of the ports using DSA
subystem, but lacking that in Barebox, creating pseudo PHYs is the
simplest option to have code to properly configure various interface
parameters.

This is needed, for example, on ZII RPU2 board where FEC is connected
directly to one of the MAC-only ports. That link requires proper RGMII
delay configuration in order to be functional.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/phy/mv88e6xxx/chip.c | 124 +++++-
 drivers/net/phy/mv88e6xxx/chip.h |  71 ++++
 drivers/net/phy/mv88e6xxx/port.c | 643 +++++++++++++++++++++++++++++++
 drivers/net/phy/mv88e6xxx/port.h |  48 +++
 4 files changed, 877 insertions(+), 9 deletions(-)

diff --git a/drivers/net/phy/mv88e6xxx/chip.c b/drivers/net/phy/mv88e6xxx/chip.c
index 7eb961fc0..ac08b5ef5 100644
--- a/drivers/net/phy/mv88e6xxx/chip.c
+++ b/drivers/net/phy/mv88e6xxx/chip.c
@@ -63,12 +63,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 = {
@@ -84,12 +92,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 = {
@@ -103,6 +119,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 = {
@@ -111,12 +132,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 = {
@@ -125,6 +156,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 = {
@@ -140,6 +176,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 = {
@@ -148,6 +189,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 = {
@@ -156,6 +202,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 = {
@@ -164,6 +215,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 = {
@@ -172,6 +228,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 = {
@@ -180,6 +241,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 = {
@@ -188,6 +253,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 = {
@@ -196,18 +265,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 = {
@@ -216,6 +300,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 = {
@@ -224,6 +313,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 = {
@@ -232,6 +327,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[] = {
@@ -761,18 +862,19 @@ static int mv88e6xxx_probe(struct device_d *dev)
 	}
 
 	/*
-	 * 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
+	 * In single-chip address mode addresses 0x10 -
+	 * port_base_address are reserved to access various switch
+	 * registers and do not correspond to any PHYs, so we mask
+	 * them to pervent from being exposed.
 	 */
-	chip->parent_miibus->phy_mask |= GENMASK(0x1f, 0x10);
+	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
+	 * Mask all of the devices on child MDIO bus. Call to
+	 * mv88e6xxx_port_probe() will unmask port that can be probed
+	 * using standard methods
 	 */
-	chip->miibus.phy_mask |= GENMASK(0x1f, 0x0f);
+	chip->miibus.phy_mask |= GENMASK(0x1f, 0x00);
 
 	chip->miibus.read = mv88e6xxx_mdio_read;
 	chip->miibus.write = mv88e6xxx_mdio_write;
@@ -784,6 +886,10 @@ static int mv88e6xxx_probe(struct device_d *dev)
 	if (mdio_node)
 		chip->miibus.dev.device_node = mdio_node;
 
+	err = mv88e6xxx_port_probe(chip);
+	if (err)
+		return err;
+
 	return mdiobus_register(&chip->miibus);
 }
 
diff --git a/drivers/net/phy/mv88e6xxx/chip.h b/drivers/net/phy/mv88e6xxx/chip.h
index 3a798a11e..7548358de 100644
--- a/drivers/net/phy/mv88e6xxx/chip.h
+++ b/drivers/net/phy/mv88e6xxx/chip.h
@@ -26,6 +26,8 @@ enum mv88e6xxx_family {
 
 struct mv88e6xxx_ops;
 
+#define DSA_MAX_PORTS		12
+
 struct mv88e6xxx_info {
 	enum mv88e6xxx_family family;
 	u16 prod_num;
@@ -37,12 +39,19 @@ struct mv88e6xxx_info {
 	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 +59,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 +81,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..52f95d622 100644
--- a/drivers/net/phy/mv88e6xxx/port.c
+++ b/drivers/net/phy/mv88e6xxx/port.c
@@ -1,6 +1,9 @@
 #include <common.h>
 #include <init.h>
 
+#include <linux/bitfield.h>
+#include <linux/marvell_phy.h>
+
 #include "port.h"
 
 int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
@@ -18,3 +21,643 @@ 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)
+{
+	u16 cmode;
+
+	if (mode == PHY_INTERFACE_MODE_NA)
+		return 0;
+
+	if (port != 9 && port != 10)
+		return -EOPNOTSUPP;
+
+	switch (mode) {
+	case PHY_INTERFACE_MODE_1000BASEX:
+		cmode = MV88E6XXX_PORT_STS_CMODE_1000BASE_X;
+		break;
+	case PHY_INTERFACE_MODE_SGMII:
+		cmode = MV88E6XXX_PORT_STS_CMODE_SGMII;
+		break;
+	case PHY_INTERFACE_MODE_2500BASEX:
+		cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX;
+		break;
+	case PHY_INTERFACE_MODE_XGMII:
+	case PHY_INTERFACE_MODE_XAUI:
+		cmode = MV88E6XXX_PORT_STS_CMODE_XAUI;
+		break;
+	case PHY_INTERFACE_MODE_RXAUI:
+		cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI;
+		break;
+	default:
+		cmode = 0;
+	}
+
+	chip->ports[port].cmode = cmode;
+
+	return 0;
+}
+
+int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
+			      struct phylink_link_state *state)
+{
+	int err;
+	u16 reg;
+
+	err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, &reg);
+	if (err)
+		return err;
+
+	switch (reg & MV88E6XXX_PORT_STS_SPEED_MASK) {
+	case MV88E6XXX_PORT_STS_SPEED_10:
+		state->speed = SPEED_10;
+		break;
+	case MV88E6XXX_PORT_STS_SPEED_100:
+		state->speed = SPEED_100;
+		break;
+	case MV88E6XXX_PORT_STS_SPEED_1000:
+		state->speed = SPEED_1000;
+		break;
+	case MV88E6XXX_PORT_STS_SPEED_10000:
+		if ((reg & MV88E6XXX_PORT_STS_CMODE_MASK) ==
+		    MV88E6XXX_PORT_STS_CMODE_2500BASEX)
+			state->speed = SPEED_2500;
+		else
+			state->speed = SPEED_10000;
+		break;
+	}
+
+	state->duplex = reg & MV88E6XXX_PORT_STS_DUPLEX ?
+			DUPLEX_FULL : DUPLEX_HALF;
+	state->link = !!(reg & MV88E6XXX_PORT_STS_LINK);
+	state->an_enabled = 1;
+	state->an_complete = state->link;
+
+	return 0;
+}
+
+int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port,
+			      struct phylink_link_state *state)
+{
+	if (state->interface == PHY_INTERFACE_MODE_1000BASEX) {
+		u8 cmode = chip->ports[port].cmode;
+
+		/* When a port is in "Cross-chip serdes" mode, it uses
+		 * 1000Base-X full duplex mode, but there is no automatic
+		 * link detection. Use the sync OK status for link (as it
+		 * would do for 1000Base-X mode.)
+		 */
+		if (cmode == MV88E6185_PORT_STS_CMODE_SERDES) {
+			u16 mac;
+			int err;
+
+			err = mv88e6xxx_port_read(chip, port,
+						  MV88E6XXX_PORT_MAC_CTL, &mac);
+			if (err)
+				return err;
+
+			state->link = !!(mac & MV88E6185_PORT_MAC_CTL_SYNC_OK);
+			state->an_enabled = 1;
+			state->an_complete =
+				!!(mac & MV88E6185_PORT_MAC_CTL_AN_DONE);
+			state->duplex =
+				state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN;
+			state->speed =
+				state->link ? SPEED_1000 : SPEED_UNKNOWN;
+
+			return 0;
+		}
+	}
+
+	return mv88e6352_port_link_state(chip, port, state);
+}
+
+
+static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
+				    int link, int speed, int duplex, int pause,
+				    phy_interface_t mode)
+{
+	int err;
+
+	if (!chip->info->ops->port_set_link)
+		return 0;
+
+	/* Port's MAC control must not be changed unless the link is down */
+	err = chip->info->ops->port_set_link(chip, port, 0);
+	if (err)
+		return err;
+
+	if (chip->info->ops->port_set_speed) {
+		err = chip->info->ops->port_set_speed(chip, port, speed);
+		if (err && err != -EOPNOTSUPP)
+			goto restore_link;
+	}
+
+	if (chip->info->ops->port_set_pause) {
+		err = chip->info->ops->port_set_pause(chip, port, pause);
+		if (err)
+			goto restore_link;
+
+	}
+
+	if (chip->info->ops->port_set_duplex) {
+		err = chip->info->ops->port_set_duplex(chip, port, duplex);
+		if (err && err != -EOPNOTSUPP)
+			goto restore_link;
+	}
+
+	if (chip->info->ops->port_set_rgmii_delay) {
+		err = chip->info->ops->port_set_rgmii_delay(chip, port, mode);
+		if (err && err != -EOPNOTSUPP)
+			goto restore_link;
+	}
+
+	if (chip->info->ops->port_set_cmode) {
+		err = chip->info->ops->port_set_cmode(chip, port, mode);
+		if (err && err != -EOPNOTSUPP)
+			goto restore_link;
+	}
+
+	err = 0;
+restore_link:
+	if (chip->info->ops->port_set_link(chip, port, link))
+		dev_err(chip->dev, "p%d: failed to restore MAC's link\n", port);
+
+	return err;
+}
+
+static int mv88e6xxx_port_config_init(struct phy_device *phydev)
+{
+	struct mv88e6xxx_chip *chip = phydev->dev.priv;
+	int port = phydev->addr - chip->info->port_base_addr;
+	int err;
+
+	err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
+				       phydev->duplex, phydev->pause,
+				       phydev->interface);
+
+	if (err && err != -EOPNOTSUPP)
+		dev_err(&phydev->dev, "p%d: failed to configure MAC\n", port);
+
+	return err;
+}
+
+static int mv88e6xxx_port_config_aneg(struct phy_device *phydev)
+{
+	return 0;
+}
+
+static int mv88e6xxx_port_read_status(struct phy_device *phydev)
+{
+	struct mv88e6xxx_chip *chip = phydev->dev.priv;
+	int port = phydev->addr - chip->info->port_base_addr;
+	struct phylink_link_state state;
+	int err;
+
+	err = mv88e6352_port_link_state(chip, port, &state);
+	if (err)
+		return err;
+
+	phydev->link = state.link;
+	phydev->duplex = state.duplex;
+	phydev->speed = state.speed;
+
+	phydev->pause = phydev->asym_pause = 0;
+
+ 	return 0;
+}
+
+/*
+ * Fake switch PHY_ID used to match this driver against devices
+ * create in mv88e6xxx_port_probe.
+ */
+#define MV88E6XXX_SWITCH_PORT_PHY_ID (0x01410000 | \
+				      MV88E6XXX_PORT_SWITCH_ID_PROD_6085)
+
+static struct phy_driver mv88e6xxx_port_driver = {
+	.phy_id         = MV88E6XXX_SWITCH_PORT_PHY_ID,
+	.phy_id_mask    = MARVELL_PHY_ID_MASK,
+	.drv.name	= "Marvel 88E6xxx Port",
+	.features	= PHY_GBIT_FEATURES & ~SUPPORTED_Autoneg,
+	.config_init	= mv88e6xxx_port_config_init,
+	.config_aneg	= mv88e6xxx_port_config_aneg,
+	.read_status	= mv88e6xxx_port_read_status,
+};
+
+static int __init mv88e6xxx_port_driver_register(void)
+{
+	return phy_driver_register(&mv88e6xxx_port_driver);
+}
+fs_initcall(mv88e6xxx_port_driver_register);
+
+int mv88e6xxx_port_probe(struct mv88e6xxx_chip *chip)
+{
+	struct device_d *dev = chip->dev;
+	struct device_node *np = dev->device_node;
+	struct device_node *port_node, *switch_node;
+	struct device_node *port_nodes[DSA_MAX_PORTS] = { NULL };
+	int err, i;
+
+	switch_node = of_find_node_by_name(np, "ports");
+	if (!switch_node)
+		return -EINVAL;
+
+ 	for_each_available_child_of_node(switch_node, port_node) {
+		u32 nr;
+
+ 		err = of_property_read_u32(port_node, "reg", &nr);
+		if (err) {
+			dev_err(dev,
+				"Error: Failed to find reg for child %s\n",
+				port_node->full_name);
+			continue;
+		}
+
+		port_nodes[nr] = port_node;
+	}
+
+	/*
+	 * Walk through all of the ports and unmask those that are
+	 * connected to a PHY via child MDIO bus, so the can be picked
+	 * up via regular PHY discover.
+	 *
+	 * While at it, also create PHY objects for ports that are
+	 * not, so they can be correctly configured
+	 */
+	for (i = 0; i < chip->info->num_ports; i++) {
+		struct phy_device *phydev;
+		u16 status;
+		bool force_mac = false;
+		int addr = i;
+
+		err = mv88e6xxx_port_read(chip, i, MV88E6XXX_PORT_STS,
+					  &status);
+		if (err)
+			return err;
+
+		/*
+		 * FIXME: This most likely affects more than 6161, so
+		 * this will have to be expanded to more chips
+		 */
+		if (chip->info->prod_num ==
+		    MV88E6XXX_PORT_SWITCH_ID_PROD_6161) {
+			const uint8_t cmode =
+				FIELD_GET(MV88E6185_PORT_STS_CMODE_MASK,
+					  status);
+			switch (i) {
+			case 4:
+			case 5:	/* FALLTHROUGH */
+				if (cmode == MV88E6165_PORT_STS_CMODE_SGMII) {
+					/*
+					 * Port is configured to SGMII
+					 * bypassing SERDES/PHY
+					 */
+					force_mac = true;
+					break;
+				}
+
+				if (cmode != MV88E6165_PORT_STS_CMODE_PHY) {
+					/*
+					 * If port is configured to
+					 * SERDES we need to adjust
+					 * its MDIO address
+					 */
+					addr += MV88E6165_PORT_SERDES_OFFSET;
+				}
+
+				break;
+			}
+		}
+
+		if (status & MV88E6XXX_PORT_STS_PHY_DETECT && !force_mac) {
+			/*
+			 * True PHYs will be automaticall handled by
+			 * generic PHY driver, so we ignore those.
+			 */
+			chip->miibus.phy_mask &= ~BIT(addr);
+			continue;
+		}
+
+		/*
+		 * In order to expose MAC-only ports on the switch, so
+		 * they can be properly configured to match other
+		 * end's settings, we create pseudo PHY devices that
+		 * will match against our special PHY driver
+		 */
+ 		phydev = phy_device_create(chip->parent_miibus,
+					   chip->info->port_base_addr + i,
+					   MV88E6XXX_SWITCH_PORT_PHY_ID);
+		phydev->dev.device_node = port_nodes[i];
+		phydev->dev.priv = chip;
+		phydev->duplex = DUPLEX_UNFORCED;
+
+		err = phy_register_device(phydev);
+		if (err)
+			dev_err(dev, "Error: Failed to register a PHY\n");
+	}
+
+	return 0;
+}
\ No newline at end of file
diff --git a/drivers/net/phy/mv88e6xxx/port.h b/drivers/net/phy/mv88e6xxx/port.h
index 7bb2e8bb4..07d937ecb 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,32 @@
 #define MV88E6XXX_PORT_STS_CMODE_2500BASEX	0x000b
 #define MV88E6XXX_PORT_STS_CMODE_XAUI		0x000c
 #define MV88E6XXX_PORT_STS_CMODE_RXAUI		0x000d
+#define MV88E6185_PORT_STS_CDUPLEX		0x0008
+#define MV88E6185_PORT_STS_CMODE_MASK		0x0007
+#define MV88E6185_PORT_STS_CMODE_GMII_FD	0x0000
+#define MV88E6185_PORT_STS_CMODE_MII_100_FD_PS	0x0001
+#define MV88E6185_PORT_STS_CMODE_MII_100	0x0002
+#define MV88E6185_PORT_STS_CMODE_MII_10		0x0003
+#define MV88E6185_PORT_STS_CMODE_SERDES		0x0004
+#define MV88E6165_PORT_STS_CMODE_PHY		0x0004
+#define MV88E6185_PORT_STS_CMODE_1000BASE_X	0x0005
+#define MV88E6185_PORT_STS_CMODE_PHY		0x0006
+#define MV88E6165_PORT_STS_CMODE_SGMII		0x0006
+#define MV88E6185_PORT_STS_CMODE_DISABLED	0x0007
+
+
 
 /* Offset 0x01: MAC (or PCS or Physical) Control Register */
 #define MV88E6XXX_PORT_MAC_CTL				0x01
 #define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_RXCLK	0x8000
 #define MV88E6XXX_PORT_MAC_CTL_RGMII_DELAY_TXCLK	0x4000
+#define MV88E6185_PORT_MAC_CTL_SYNC_OK			0x4000
 #define MV88E6390_PORT_MAC_CTL_FORCE_SPEED		0x2000
 #define MV88E6390_PORT_MAC_CTL_ALTSPEED			0x1000
 #define MV88E6352_PORT_MAC_CTL_200BASE			0x1000
+#define MV88E6185_PORT_MAC_CTL_AN_EN			0x0400
+#define MV88E6185_PORT_MAC_CTL_AN_RESTART		0x0200
+#define MV88E6185_PORT_MAC_CTL_AN_DONE			0x0100
 #define MV88E6XXX_PORT_MAC_CTL_FC			0x0080
 #define MV88E6XXX_PORT_MAC_CTL_FORCE_FC			0x0040
 #define MV88E6XXX_PORT_MAC_CTL_LINK_UP			0x0020
@@ -80,10 +99,39 @@
 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6390	0x3900
 #define MV88E6XXX_PORT_SWITCH_ID_REV_MASK	0x000f
 
+
+/*
+ * SERDES connected to port 0x04 is accessible at address 0xC
+ */
+#define MV88E6165_PORT_SERDES_OFFSET		(0x0C - 0x04)
+
 int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port, int reg,
 			u16 *val);
 int mv88e6xxx_port_write(struct mv88e6xxx_chip *chip, int port, int reg,
 			 u16 val);
 
+int mv88e6185_port_set_pause(struct mv88e6xxx_chip *chip, int port,
+			     int pause);
+int mv88e6352_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
+				   phy_interface_t mode);
+int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port,
+				   phy_interface_t mode);
+int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link);
+int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup);
+int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
+int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
+			      phy_interface_t mode);
+int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port,
+			      struct phylink_link_state *state);
+int mv88e6185_port_link_state(struct mv88e6xxx_chip *chip, int port,
+			      struct phylink_link_state *state);
+
+/* Barebox specific */
+int mv88e6xxx_port_probe(struct mv88e6xxx_chip *chip);
+
 
 #endif /* _MV88E6XXX_PORT_H */
-- 
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 v4 00/22] MV88E6xxx switch family support
  2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
                   ` (21 preceding siblings ...)
  2018-10-16 19:15 ` [PATCH v4 22/22] net: phy: mv88e6xxx: Add support for MAC ports Andrey Smirnov
@ 2018-10-18  7:02 ` Sascha Hauer
  22 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2018-10-18  7:02 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Tue, Oct 16, 2018 at 12:15:30PM -0700, Andrey Smirnov wrote:
> Everyone:
> 
> Patches in this series are a result of my work on porting Linux code
> for MV88E6xxx switches to Barebox.
> 
> 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!

Applied, thanks

Sascha

> 
> Changes since [v3]:
> 
>    - Fix spaces/tabs mixup, missing newlines
> 
> Changes since [v2]:
> 
>    - Added code to deal with port layout on MV88E6161
> 
>    - Removed unused, #ifdefed-out code
> 
>    - basename() re-implemented using kbasename()
> 
>    - Added patches to deal with device name collision in aiodev
>      reported by Lucas
> 
>    - Patch introducing dev_set_name() was split in two
> 
>    - Added fix for dev_id()'s global buffer "collision"
> 
>    - Removed a patch hunk for code that's not yet in "next"
> 
> Changes since [v1]:
> 
>     - CONFIG_CLOCKSOURCE_ARM_GLOBAL_TIMER is not selected by
>       default. VF610 now selects it explicitly
> 
>     - Incorrect logic in patch 14/17 was fixed to correctly handle PHY
>       nodes that have "compatible" property
> 
>     - Added more documentation for dev_set_name()
> 
> [v3] http://lists.infradead.org/pipermail/barebox/2018-October/035015.html
> [v2] http://lists.infradead.org/pipermail/barebox/2018-October/034965.html
> [v1] http://lists.infradead.org/pipermail/barebox/2018-October/034963.html
> 
> Andrey Smirnov (22):
>   ARM: Do not expose ARMv8 functions on ARMv7
>   clocksource: Add ARM global timer support
>   VFxxx: Select CLOCKSOURCE_ARM_GLOBAL_TIMER
>   i.MX: Move GPT driver to drivers/clocksource
>   clocksource: Introduce ARCH_HAS_IMX_GPT
>   of: Demote "Bad cell count for" to debug
>   aiodev: Don't try to use DT node name as aiodev->name
>   aiodev: imx_thermal: Give aiodev a more descriptive name
>   aiodev: qoriq_thermal: Give aiodev a more descriptive name
>   drivers: Introduce dev_set_name()
>   base: Don't use shared buffer for results of dev_id()
>   drivers: base: Convert device_d name to be dynamically allocated
>   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                     |  12 +
>  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                         |   4 +-
>  drivers/aiodev/imx_thermal.c                  |   1 +
>  drivers/aiodev/qoriq_thermal.c                |   1 +
>  drivers/amba/bus.c                            |   2 +-
>  drivers/ata/disk_ata_drive.c                  |   4 +-
>  drivers/base/bus.c                            |   2 +-
>  drivers/base/driver.c                         |  45 +-
>  drivers/base/resource.c                       |   2 +-
>  drivers/clocksource/Kconfig                   |  10 +
>  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/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                    |  27 +-
>  drivers/net/phy/mv88e6xxx/Makefile            |   5 +
>  drivers/net/phy/mv88e6xxx/chip.c              | 913 ++++++++++++++++++
>  drivers/net/phy/mv88e6xxx/chip.h              | 142 +++
>  drivers/net/phy/mv88e6xxx/global2.c           | 389 ++++++++
>  drivers/net/phy/mv88e6xxx/global2.h           |  70 ++
>  drivers/net/phy/mv88e6xxx/port.c              | 663 +++++++++++++
>  drivers/net/phy/mv88e6xxx/port.h              | 137 +++
>  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                              |  25 +-
>  include/linux/ethtool.h                       |   3 +
>  include/linux/phy.h                           |   9 +
>  include/linux/string.h                        |  12 +
>  lib/libgen.c                                  |  16 +-
>  net/eth.c                                     |   2 +-
>  68 files changed, 2649 insertions(+), 155 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
> 

-- 
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

end of thread, other threads:[~2018-10-18  7:02 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-16 19:15 [PATCH v4 00/22] MV88E6xxx switch family support Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 01/22] ARM: Do not expose ARMv8 functions on ARMv7 Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 02/22] clocksource: Add ARM global timer support Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 03/22] VFxxx: Select CLOCKSOURCE_ARM_GLOBAL_TIMER Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 04/22] i.MX: Move GPT driver to drivers/clocksource Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 05/22] clocksource: Introduce ARCH_HAS_IMX_GPT Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 06/22] of: Demote "Bad cell count for" to debug Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 07/22] aiodev: Don't try to use DT node name as aiodev->name Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 08/22] aiodev: imx_thermal: Give aiodev a more descriptive name Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 09/22] aiodev: qoriq_thermal: " Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 10/22] drivers: Introduce dev_set_name() Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 11/22] base: Don't use shared buffer for results of dev_id() Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 12/22] drivers: base: Convert device_d name to be dynamically allocated Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 13/22] linux: string: Port kbasename() Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 14/22] of: Port latest of_device_make_bus_id() implementation Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 15/22] mdio_bus: Fix documentation for mdio_bus_match() Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 16/22] include: linux: phy: Add missing PHY_INTERFACE_* constants Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 17/22] include: linux: ethtool: Add missing *_UNKNOWN constants Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 18/22] net: phy: Check phy_mask in get_phy_device() Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 19/22] mdio_bus: Allow for non PHY-devices on MDIO buses Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 20/22] net: phy: Add basic driver for MV88E6XXX switches from Marvell Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 21/22] net: phy: mv88e6xxx: Port EEPROM support code Andrey Smirnov
2018-10-16 19:15 ` [PATCH v4 22/22] net: phy: mv88e6xxx: Add support for MAC ports Andrey Smirnov
2018-10-18  7:02 ` [PATCH v4 00/22] MV88E6xxx switch family support Sascha Hauer

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