All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support
@ 2015-05-22  1:07 Ray Jui
  2015-05-22  1:07 ` [PATCH v2 1/5] dt_bindings: Add iProc MDC/MDIO interface binding Ray Jui
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Ray Jui @ 2015-05-22  1:07 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Arnd Bergmann
  Cc: linux-kernel, JD (Jiandong) Zheng, Arun Parameswaran,
	bcm-kernel-feedback-list, Ray Jui

This patch series adds support for the Cygnus PCIe PHY and support of the
MDC/MDIO bus interface found in various iProc based of SoCs. The iProc
MDC/MDIO bus interface can be used by the host processor to communicate with
various internal Serdes/PHYs including Ethernet, PCIe, USB, etc.

This patch series is based on Linux v4.1-rc4 and is avaliable in:
https://github.com/Broadcom/cygnus-linux/tree/cygnus-pcie-phy-v2

Changes from v1:
 - Move the MDC/MDIO bus driver from drivers/phy/* to drivers/bus/*
 - Make the PCIe PHY device node child node of the MDIO bus
 - Change the PCIe PHY driver to tristate so it can be compiled as a module
 - Other minor changes

Ray Jui (5):
  dt_bindings: Add iProc MDC/MDIO interface binding
  phy: iproc-mdio: Initial iProc MDC/MDIO support
  phy: cygnus: pcie: Define DT binding
  phy: cygnus: pcie: Add Cygnus PCIe PHY support
  ARM: dts: enable PCIe PHY support for Cygnus

 .../devicetree/bindings/bus/brcm,iproc-mdio.txt    |   21 ++
 .../bindings/phy/brcm,cygnus-pcie-phy.txt          |   34 ++
 arch/arm/boot/dts/bcm-cygnus.dtsi                  |   20 ++
 drivers/bus/Kconfig                                |   12 +
 drivers/bus/Makefile                               |    1 +
 drivers/bus/iproc-mdio-bus.c                       |  255 +++++++++++++++
 drivers/phy/Kconfig                                |   15 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-cygnus-pcie.c                      |  340 ++++++++++++++++++++
 include/linux/iproc_mdio_bus.h                     |   22 ++
 10 files changed, 721 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/brcm,iproc-mdio.txt
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt
 create mode 100644 drivers/bus/iproc-mdio-bus.c
 create mode 100644 drivers/phy/phy-cygnus-pcie.c
 create mode 100644 include/linux/iproc_mdio_bus.h

-- 
1.7.9.5


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

* [PATCH v2 1/5] dt_bindings: Add iProc MDC/MDIO interface binding
  2015-05-22  1:07 [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
@ 2015-05-22  1:07 ` Ray Jui
  2015-05-22  1:07 ` [PATCH v2 2/5] phy: iproc-mdio: Initial iProc MDC/MDIO support Ray Jui
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Ray Jui @ 2015-05-22  1:07 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Arnd Bergmann
  Cc: linux-kernel, JD (Jiandong) Zheng, Arun Parameswaran,
	bcm-kernel-feedback-list, Ray Jui

Define device tree bindings for iProc MDC/MDIO bus interface

Signed-off-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 .../devicetree/bindings/bus/brcm,iproc-mdio.txt    |   21 ++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/brcm,iproc-mdio.txt

diff --git a/Documentation/devicetree/bindings/bus/brcm,iproc-mdio.txt b/Documentation/devicetree/bindings/bus/brcm,iproc-mdio.txt
new file mode 100644
index 0000000..db7228b
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/brcm,iproc-mdio.txt
@@ -0,0 +1,21 @@
+Broadcom iProc MDC/MDIO bus interface
+
+The iProc MDC/MDIO bus interface is found on various iProc based SoCs and is
+used to communicate with various types of Serdes/PHYs including Ethernet,
+PCIe, USB, and etc.
+
+Required properties:
+- compatible: Must be "brcm,iproc-mdio"
+- reg: base address and length of the MDC/MDIO interface
+- address-cells: must be 1
+- size-cells: must be 1
+- ranges: leave it empty
+
+Example:
+	mdio_bus: mdio_bus@18002000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "brcm,iproc-mdio";
+		ranges;
+		reg = <0x18002000 0x8>;
+	};
-- 
1.7.9.5


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

* [PATCH v2 2/5] phy: iproc-mdio: Initial iProc MDC/MDIO support
  2015-05-22  1:07 [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
  2015-05-22  1:07 ` [PATCH v2 1/5] dt_bindings: Add iProc MDC/MDIO interface binding Ray Jui
@ 2015-05-22  1:07 ` Ray Jui
  2015-05-22  1:07 ` [PATCH v2 3/5] phy: cygnus: pcie: Define DT binding Ray Jui
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Ray Jui @ 2015-05-22  1:07 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Arnd Bergmann
  Cc: linux-kernel, JD (Jiandong) Zheng, Arun Parameswaran,
	bcm-kernel-feedback-list, Ray Jui

This adds the support for the iProc MDC/MDIO bus interface. Various
iProc SoCs can use the MDC/MDIO bus interface to communicate with
various Serdes/PHYs including Ethernet, PCIe, USB, etc.

Signed-off-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/bus/Kconfig            |   12 ++
 drivers/bus/Makefile           |    1 +
 drivers/bus/iproc-mdio-bus.c   |  255 ++++++++++++++++++++++++++++++++++++++++
 include/linux/iproc_mdio_bus.h |   22 ++++
 4 files changed, 290 insertions(+)
 create mode 100644 drivers/bus/iproc-mdio-bus.c
 create mode 100644 include/linux/iproc_mdio_bus.h

diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index a1d4af6..99b38cb 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -55,6 +55,18 @@ config IMX_WEIM
 	  The WEIM(Wireless External Interface Module) works like a bus.
 	  You can attach many different devices on it, such as NOR, onenand.
 
+config IPROC_MDIO
+	bool "Broadcom iProc MDC/MDIO driver"
+	depends on ARCH_BCM_IPROC
+	default ARCH_BCM_IPROC
+	help
+	  Enable this to support the iProc generic MDC/MDIO bus interface found
+	  in various iProc based SoCs. The generic MDC/MDIO bus interface can
+	  be used to communicate with various types of Serdes/PHYs including
+	  Ethernet, PCIe, USB, and etc.
+
+	  If unsure, say N.
+
 config MIPS_CDMM
 	bool "MIPS Common Device Memory Map (CDMM) Driver"
 	depends on CPU_MIPSR2
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 790e7b9..6dff76a 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_ARM_CCN)		+= arm-ccn.o
 
 obj-$(CONFIG_BRCMSTB_GISB_ARB)	+= brcmstb_gisb.o
 obj-$(CONFIG_IMX_WEIM)		+= imx-weim.o
+obj-$(CONFIG_IPROC_MDIO)	+= iproc-mdio-bus.o
 obj-$(CONFIG_MIPS_CDMM)		+= mips_cdmm.o
 obj-$(CONFIG_MVEBU_MBUS) 	+= mvebu-mbus.o
 
diff --git a/drivers/bus/iproc-mdio-bus.c b/drivers/bus/iproc-mdio-bus.c
new file mode 100644
index 0000000..ae91722
--- /dev/null
+++ b/drivers/bus/iproc-mdio-bus.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/iproc_mdio_bus.h>
+
+#define MDIO_TIMEOUT_MSEC             10
+
+#define MDC_CTRL_OFFSET               0x000
+
+#define MDC_CTRL_DIV_SHIFT            0
+#define MDC_CTRL_DIV_WIDTH            7
+#define MDC_MAX_DIV                   (BIT(MDC_CTRL_DIV_WIDTH) - 1)
+#define MDC_CTRL_PRE_SHIFT            7
+#define MDC_CTRL_BUSY_SHIFT           8
+#define MDC_CTRL_EXT_SHIFT            9
+#define MDC_CTRL_BTP_SHIFT            10
+
+#define MDC_DATA_OFFSET               0x004
+
+#define MDC_DATA_SHIFT                0
+#define MDC_DATA_MASK                 0xffff
+
+#define MDC_DATA_TA_SHIFT             16
+#define MDC_DATA_TA_VAL               2
+
+#define MDC_DATA_RA_SHIFT             18
+#define MDC_DATA_RA_WIDTH             5
+#define MDC_MAX_RA                    (BIT(MDC_DATA_RA_WIDTH) - 1)
+
+#define MDC_DATA_PA_SHIFT             23
+#define MDC_DATA_PA_WIDTH             5
+#define MDC_MAX_PA                    (BIT(MDC_DATA_PA_WIDTH) - 1)
+
+#define MDC_DATA_OP_SHIFT             28
+#define MDC_DATA_OP_WRITE             1
+#define MDC_DATA_OP_READ              2
+
+#define MDC_DATA_SB_SHIFT             30
+
+/**
+ * struct iproc_mdc - iProc MDC/MDIO bus interface
+ * @dev: pointer to device
+ * @base: MDC controller register base pointer
+ * @lock: mutex to protect access to the MDC device
+ * @is_ready: flag to indicate the driver has been initialized and is ready for
+ * use
+ */
+struct iproc_mdc {
+	struct device *dev;
+	void __iomem *base;
+	struct mutex lock;
+	bool is_ready;
+};
+
+static struct iproc_mdc iproc_mdc;
+
+static inline int iproc_mdio_check_params(unsigned clk_div, unsigned pa,
+					  unsigned ra)
+{
+	if (clk_div > MDC_MAX_DIV || pa > MDC_MAX_PA || ra > MDC_MAX_RA)
+		return -EINVAL;
+
+	return 0;
+}
+
+static inline int iproc_mdio_wait_for_idle(void __iomem *base)
+{
+	u32 val;
+	unsigned long timeout = jiffies + msecs_to_jiffies(MDIO_TIMEOUT_MSEC);
+
+	while (!time_after(jiffies, timeout)) {
+		val = readl(base + MDC_CTRL_OFFSET);
+		if ((val & BIT(MDC_CTRL_BUSY_SHIFT)) == 0)
+			return 0;
+
+		cpu_relax();
+	}
+
+	return -ETIMEDOUT;
+}
+
+static inline void iproc_mdio_config_clk(void __iomem *base, unsigned clk_div)
+{
+	u32 val;
+
+	val = (clk_div << MDC_CTRL_DIV_SHIFT) | BIT(MDC_CTRL_PRE_SHIFT);
+	writel(val, base + MDC_CTRL_OFFSET);
+}
+
+static int iproc_mdio_read_write(void __iomem *base, bool dir_is_write,
+				 unsigned clk_div, unsigned pa, unsigned ra,
+				 u16 *data)
+{
+	int ret;
+	u32 val;
+
+	ret = iproc_mdio_check_params(clk_div, pa, ra);
+	if (ret)
+		return ret;
+
+	ret = iproc_mdio_wait_for_idle(base);
+	if (ret)
+		return ret;
+
+	iproc_mdio_config_clk(base, clk_div);
+
+	ret = iproc_mdio_wait_for_idle(base);
+	if (ret)
+		return ret;
+
+	val = (MDC_DATA_TA_VAL << MDC_DATA_TA_SHIFT) |
+		(ra << MDC_DATA_RA_SHIFT) |
+		(pa << MDC_DATA_PA_SHIFT) |
+		BIT(MDC_DATA_SB_SHIFT);
+
+	if (dir_is_write) {
+		val |= (MDC_DATA_OP_WRITE << MDC_DATA_OP_SHIFT);
+		val |= ((u32)(*data) & MDC_DATA_MASK);
+	} else {
+		val |= (MDC_DATA_OP_READ << MDC_DATA_OP_SHIFT);
+	}
+
+	writel(val, base + MDC_DATA_OFFSET);
+
+	ret = iproc_mdio_wait_for_idle(base);
+	if (ret)
+		return ret;
+
+	if (!dir_is_write) {
+		val = readl(base + MDC_DATA_OFFSET) & MDC_DATA_MASK;
+		*data = (u16)val;
+	}
+
+	return 0;
+}
+
+
+/**
+ * iproc_mdio_read() - read from a PHY register through the MDC interface
+ *
+ * @clk_div: MDC clock divisor
+ * @phy_addr: MDC PHY address
+ * @reg_addr: PHY register address
+ * @data: pointer to the memory where data will be stored
+ */
+int iproc_mdio_read(unsigned clk_div, unsigned phy_addr, unsigned reg_addr,
+		    u16 *data)
+{
+	int ret;
+	struct iproc_mdc *mdc = &iproc_mdc;
+
+	if (!mdc->is_ready)
+		return -ENODEV;
+
+	mutex_lock(&mdc->lock);
+	ret = iproc_mdio_read_write(mdc->base, false, clk_div, phy_addr,
+				    reg_addr, data);
+	if (ret)
+		dev_err(mdc->dev, "mdio read failed\n");
+	mutex_unlock(&mdc->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(iproc_mdio_read);
+
+/**
+ * iproc_mdio_write() - write to a PHY register through the MDC interface
+ *
+ * @clk_div: MDC clock divisor
+ * @phy_addr: MDC PHY address
+ * @reg_addr: PHY register address
+ * @data: data value to be written to the PHY register
+ */
+int iproc_mdio_write(unsigned clk_div, unsigned phy_addr, unsigned reg_addr,
+		     u16 data)
+{
+	int ret;
+	struct iproc_mdc *mdc = &iproc_mdc;
+
+	if (!mdc->is_ready)
+		return -ENODEV;
+
+	mutex_lock(&mdc->lock);
+	ret = iproc_mdio_read_write(mdc->base, true, clk_div, phy_addr,
+				    reg_addr, &data);
+	if (ret)
+		dev_err(mdc->dev, "mdio write failed\n");
+	mutex_unlock(&mdc->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(iproc_mdio_write);
+
+static int iproc_mdio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct iproc_mdc *mdc = &iproc_mdc;
+	struct resource *res;
+
+	mdc->dev = dev;
+	mutex_init(&mdc->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mdc->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(mdc->base))
+		return PTR_ERR(mdc->base);
+
+	mdc->is_ready = true;
+
+	if (np)
+		of_platform_populate(np, NULL, NULL, dev);
+
+	return 0;
+}
+
+static const struct of_device_id iproc_mdio_match_table[] = {
+	{ .compatible = "brcm,iproc-mdio" },
+	{ }
+};
+
+static struct platform_driver iproc_mdio_driver = {
+	.driver = {
+		.name = "iproc-mdio",
+		.of_match_table = iproc_mdio_match_table,
+		.suppress_bind_attrs = true,
+	},
+	.probe	= iproc_mdio_probe,
+};
+
+static int __init iproc_mdio_init(void)
+{
+	return platform_driver_register(&iproc_mdio_driver);
+}
+arch_initcall_sync(iproc_mdio_init);
+
+MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom iPROC MDC/MDIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/iproc_mdio_bus.h b/include/linux/iproc_mdio_bus.h
new file mode 100644
index 0000000..4d1235a
--- /dev/null
+++ b/include/linux/iproc_mdio_bus.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __IPROC_MDIO_BUS_H
+#define __IPROC_MDIO_BUS_H
+
+int iproc_mdio_read(unsigned clk_div, unsigned phy_addr, unsigned reg_addr,
+		    u16 *data);
+int iproc_mdio_write(unsigned clk_div, unsigned phy_addr, unsigned reg_addr,
+		     u16 data);
+
+#endif /* __IPROC_MDIO_BUS_H */
-- 
1.7.9.5


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

* [PATCH v2 3/5] phy: cygnus: pcie: Define DT binding
  2015-05-22  1:07 [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
  2015-05-22  1:07 ` [PATCH v2 1/5] dt_bindings: Add iProc MDC/MDIO interface binding Ray Jui
  2015-05-22  1:07 ` [PATCH v2 2/5] phy: iproc-mdio: Initial iProc MDC/MDIO support Ray Jui
@ 2015-05-22  1:07 ` Ray Jui
  2015-05-22  1:07 ` [PATCH v2 4/5] phy: cygnus: pcie: Add Cygnus PCIe PHY support Ray Jui
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Ray Jui @ 2015-05-22  1:07 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Arnd Bergmann
  Cc: linux-kernel, JD (Jiandong) Zheng, Arun Parameswaran,
	bcm-kernel-feedback-list, Ray Jui

Add DT binding document for Broadcom Cygnus PCIe PHY driver

Signed-off-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 .../bindings/phy/brcm,cygnus-pcie-phy.txt          |   34 ++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt

diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt
new file mode 100644
index 0000000..1b1a7af
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt
@@ -0,0 +1,34 @@
+Broadcom Cygnus PCIe PHY
+
+Required properties:
+- compatible: Must be "brcm,cygnus-pcie-phy"
+- reg: base address and length of the CRMU block
+- #phy-cells: must be <2>
+The first cell is the PHY ID:
+0 - PCIe RC 0
+1 - PCIe RC 1
+The second cell is the internal PHY address
+
+Example:
+	mdio_bus {
+		...
+		phy: phy@0301d0a0 {
+			compatible = "brcm,cygnus-pcie-phy";
+			reg = <0x0301d0a0 0x14>;
+			#phy-cells = <2>;
+		};
+	};
+
+	pcie0: pcie@18012000 {
+		...
+		...
+		phys = <&phy 0 5>;
+		phy-names = "pcie-phy";
+	};
+
+	pcie1: pcie@18013000 {
+		...
+		...
+		phys = <&phy 1 6>;
+		phy-names = "pcie-phy";
+	};
-- 
1.7.9.5


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

* [PATCH v2 4/5] phy: cygnus: pcie: Add Cygnus PCIe PHY support
  2015-05-22  1:07 [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
                   ` (2 preceding siblings ...)
  2015-05-22  1:07 ` [PATCH v2 3/5] phy: cygnus: pcie: Define DT binding Ray Jui
@ 2015-05-22  1:07 ` Ray Jui
  2015-05-22  1:07 ` [PATCH v2 5/5] ARM: dts: enable PCIe PHY support for Cygnus Ray Jui
  2015-09-01 21:13 ` [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
  5 siblings, 0 replies; 7+ messages in thread
From: Ray Jui @ 2015-05-22  1:07 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Arnd Bergmann
  Cc: linux-kernel, JD (Jiandong) Zheng, Arun Parameswaran,
	bcm-kernel-feedback-list, Ray Jui

This patch adds the PCIe PHY support for the Broadcom PCIe RC interface

Signed-off-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/phy/Kconfig           |   15 ++
 drivers/phy/Makefile          |    1 +
 drivers/phy/phy-cygnus-pcie.c |  340 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 356 insertions(+)
 create mode 100644 drivers/phy/phy-cygnus-pcie.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index a53bd5b..ba1954f 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -35,6 +35,21 @@ config ARMADA375_USBCLUSTER_PHY
 	depends on OF
 	select GENERIC_PHY
 
+config PHY_CYGNUS_PCIE
+	tristate "Broadcom Cygnus PCIe PHY driver"
+	depends on ARCH_BCM_CYGNUS
+	select GENERIC_PHY
+	select IPROC_MDIO
+	default ARCH_BCM_CYGNUS
+	help
+	  Enable this to support the Broadcom Cygnus PCIe PHY.
+
+	  The host communicates with the PHY through the iProc MDC/MDIO
+	  interface.
+
+	  If unsure, say N.
+
+
 config PHY_DM816X_USB
 	tristate "TI dm816x USB PHY driver"
 	depends on ARCH_OMAP2PLUS
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index f126251..0a4a6c8 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -5,6 +5,7 @@
 obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
 obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
 obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
+obj-$(CONFIG_PHY_CYGNUS_PCIE)		+= phy-cygnus-pcie.o
 obj-$(CONFIG_PHY_DM816X_USB)		+= phy-dm816x-usb.o
 obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
 obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
diff --git a/drivers/phy/phy-cygnus-pcie.c b/drivers/phy/phy-cygnus-pcie.c
new file mode 100644
index 0000000..b00a587
--- /dev/null
+++ b/drivers/phy/phy-cygnus-pcie.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/iproc_mdio_bus.h>
+
+#define MAX_PHY_ADDR                  0x1f
+
+#define PCIE_MDCDIV_VAL               0x3e
+
+#define PCIE_BLK_ADDR_OFFSET          0x1f
+#define PCIE_BLK_ADDR_MASK            0xff00
+#define PCIE_REG_ADDR_MASK            0x1f
+
+#define PCIE_SW_CTRL0_OFFSET          0x1000
+#define PCIE_SW_PWRDOWN_SHIFT         0
+
+#define PCIE_AFE1_100MHZ_C3_OFFSET    0x2103
+#define PCIE_AFE1_100MHZ_C3_VAL       0x2b1c
+
+#define CRMU_PCIE_CFG_OFFSET          0x00
+#define CRMU_PCIE1_PHY_IDDQ_SHIFT     10
+#define CRMU_PCIE0_PHY_IDDQ_SHIFT     2
+
+enum cygnus_pcie_phy_id {
+	CYGNUS_PHY_PCIE0 = 0,
+	CYGNUS_PHY_PCIE1,
+	MAX_NUM_PHYS,
+};
+
+struct cygnus_pcie_phy_core;
+
+/**
+ * struct cygnus_pcie_phy - Cygnus PCIe PHY device
+ * @core: pointer to the Cygnus PCIe PHY core control
+ * @id: internal ID to identify the Cygnus PCIe PHY
+ * @addr: PHY address used by MDC to communicate with the PHY
+ * @phy: pointer to the kernel PHY device
+ *
+ */
+struct cygnus_pcie_phy {
+	struct cygnus_pcie_phy_core *core;
+	enum cygnus_pcie_phy_id id;
+	unsigned addr;
+	struct phy *phy;
+};
+
+/**
+ * struct cygnus_pcie_phy_core - Cygnus PCIe PHY core control
+ * @dev: pointer to device
+ * @crmu: CRMU register base
+ * @lock: mutex to protect access to individual PHYs
+ * @phys: pointer to Cygnus PHY device
+ *
+ */
+struct cygnus_pcie_phy_core {
+	struct device *dev;
+	void __iomem *crmu;
+	struct mutex lock;
+	struct cygnus_pcie_phy phys[MAX_NUM_PHYS];
+};
+
+static int cygnus_pcie_phy_reg_read(unsigned phy_addr, unsigned reg_addr,
+				    u16 *val)
+{
+	int ret;
+	u16 addr = (u16)(reg_addr & PCIE_BLK_ADDR_MASK);
+
+	ret = iproc_mdio_write(PCIE_MDCDIV_VAL, phy_addr, PCIE_BLK_ADDR_OFFSET,
+			       addr);
+	if (ret)
+		return ret;
+
+	ret = iproc_mdio_read(PCIE_MDCDIV_VAL, phy_addr,
+			      reg_addr & PCIE_REG_ADDR_MASK, val);
+	return ret;
+}
+
+static int cygnus_pcie_phy_reg_write(unsigned phy_addr, unsigned reg_addr,
+				     u16 val)
+{
+	int ret;
+	u16 addr = (u16)(reg_addr & PCIE_BLK_ADDR_MASK);
+
+	ret = iproc_mdio_write(PCIE_MDCDIV_VAL, phy_addr, PCIE_BLK_ADDR_OFFSET,
+			       addr);
+	if (ret)
+		return ret;
+
+	ret = iproc_mdio_write(PCIE_MDCDIV_VAL, phy_addr,
+			       reg_addr & PCIE_REG_ADDR_MASK, val);
+	return ret;
+}
+
+static void cygnus_pcie_afe_enable_disable(void __iomem *reg,
+					   enum cygnus_pcie_phy_id id,
+					   bool enable)
+{
+	unsigned shift;
+	u32 val;
+
+	if (id == CYGNUS_PHY_PCIE0)
+		shift = CRMU_PCIE0_PHY_IDDQ_SHIFT;
+	else
+		shift = CRMU_PCIE1_PHY_IDDQ_SHIFT;
+
+	if (enable) {
+		val = readl(reg + CRMU_PCIE_CFG_OFFSET);
+		val &= ~BIT(shift);
+		writel(val, reg + CRMU_PCIE_CFG_OFFSET);
+	} else {
+		val = readl(reg + CRMU_PCIE_CFG_OFFSET);
+		val |= BIT(shift);
+		writel(val, reg + CRMU_PCIE_CFG_OFFSET);
+	}
+
+	/* wait for AFE to come up or shut down */
+	msleep(100);
+}
+
+static int cygnus_pcie_power_config(struct cygnus_pcie_phy *phy, bool on)
+{
+	struct cygnus_pcie_phy_core *core = phy->core;
+	u16 val;
+	int ret;
+
+	if (phy->id != CYGNUS_PHY_PCIE0 && phy->id != CYGNUS_PHY_PCIE1)
+		return -EINVAL;
+
+	if (on) {
+		/* enable AFE through the CRMU interface */
+		cygnus_pcie_afe_enable_disable(core->crmu, phy->id, true);
+
+		/* to get the reference clock configured */
+		ret = cygnus_pcie_phy_reg_write(phy->addr,
+						PCIE_AFE1_100MHZ_C3_OFFSET,
+						PCIE_AFE1_100MHZ_C3_VAL);
+		if (ret)
+			goto err_disable_afe;
+		cygnus_pcie_phy_reg_read(phy->addr,
+					 PCIE_AFE1_100MHZ_C3_OFFSET, &val);
+		if (ret)
+			goto err_disable_afe;
+
+		msleep(20);
+
+		/* now toggle AFE */
+		cygnus_pcie_afe_enable_disable(core->crmu, phy->id, false);
+		cygnus_pcie_afe_enable_disable(core->crmu, phy->id, true);
+
+		dev_info(core->dev,
+			 "pcie phy on, addr:0x%02x off:0x%04x val:0x%04x\n",
+			 phy->addr, PCIE_AFE1_100MHZ_C3_OFFSET, val);
+	} else {
+		/* disable AFE through the CRMU interface */
+		cygnus_pcie_afe_enable_disable(core->crmu, phy->id, false);
+		dev_info(core->dev, "pcie phy off\n");
+	}
+
+	return 0;
+
+err_disable_afe:
+	cygnus_pcie_afe_enable_disable(core->crmu, phy->id, false);
+	return ret;
+}
+
+static int cygnus_pcie_phy_init(struct phy *p)
+{
+	return 0;
+}
+
+static int cygnus_pcie_phy_exit(struct phy *p)
+{
+	return 0;
+}
+
+static int cygnus_pcie_phy_power_on(struct phy *p)
+{
+	struct cygnus_pcie_phy *phy = phy_get_drvdata(p);
+	struct cygnus_pcie_phy_core *core = phy->core;
+	int ret = 0;
+
+	mutex_lock(&core->lock);
+
+	switch (phy->id) {
+	case CYGNUS_PHY_PCIE0:
+	case CYGNUS_PHY_PCIE1:
+		ret = cygnus_pcie_power_config(phy, true);
+		if (ret)
+			dev_err(core->dev, "unable to power on PCIe PHY\n");
+		break;
+
+	default:
+		dev_err(core->dev, "PHY id not supported\n");
+		mutex_unlock(&core->lock);
+		return -EINVAL;
+	}
+
+	mutex_unlock(&core->lock);
+
+	return ret;
+}
+
+static int cygnus_pcie_phy_power_off(struct phy *p)
+{
+	struct cygnus_pcie_phy *phy = phy_get_drvdata(p);
+	struct cygnus_pcie_phy_core *core = phy->core;
+	int ret = 0;
+
+	mutex_lock(&core->lock);
+
+	switch (phy->id) {
+	case CYGNUS_PHY_PCIE0:
+	case CYGNUS_PHY_PCIE1:
+		ret = cygnus_pcie_power_config(phy, false);
+		if (ret)
+			dev_err(core->dev, "unable to power off PCIe PHY\n");
+		break;
+
+	default:
+		dev_err(core->dev, "PHY id not supported\n");
+		mutex_unlock(&core->lock);
+		break;
+	}
+
+	mutex_unlock(&core->lock);
+
+	return ret;
+}
+
+static struct phy_ops cygnus_pcie_phy_ops = {
+	.init = cygnus_pcie_phy_init,
+	.exit = cygnus_pcie_phy_exit,
+	.power_on = cygnus_pcie_phy_power_on,
+	.power_off = cygnus_pcie_phy_power_off,
+};
+
+static struct phy *cygnus_pcie_phy_xlate(struct device *dev,
+					 struct of_phandle_args *args)
+{
+	struct cygnus_pcie_phy_core *core;
+	int id, phy_addr;
+
+	core = dev_get_drvdata(dev);
+	if (!core)
+		return ERR_PTR(-EINVAL);
+
+	id = args->args[0];
+	phy_addr = args->args[1];
+
+	if (WARN_ON(id >= MAX_NUM_PHYS))
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(phy_addr > MAX_PHY_ADDR))
+		return ERR_PTR(-ENODEV);
+
+	core->phys[id].addr = phy_addr;
+
+	return core->phys[id].phy;
+}
+
+static int cygnus_pcie_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cygnus_pcie_phy_core *core;
+	struct phy_provider *provider;
+	struct resource *res;
+	int i = 0;
+
+	core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
+	if (!core)
+		return -ENOMEM;
+
+	core->dev = dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	core->crmu = devm_ioremap_resource(dev, res);
+	if (IS_ERR(core->crmu))
+		return PTR_ERR(core->crmu);
+
+	mutex_init(&core->lock);
+
+	for (i = 0; i < MAX_NUM_PHYS; i++) {
+		struct cygnus_pcie_phy *p = &core->phys[i];
+
+		p->phy = devm_phy_create(dev, NULL, &cygnus_pcie_phy_ops);
+		if (IS_ERR(p->phy)) {
+			dev_err(dev, "failed to create PHY\n");
+			return PTR_ERR(p->phy);
+		}
+
+		p->core = core;
+		p->id = i;
+		phy_set_drvdata(p->phy, p);
+	}
+
+	dev_set_drvdata(dev, core);
+
+	provider = devm_of_phy_provider_register(dev, cygnus_pcie_phy_xlate);
+	if (IS_ERR(provider)) {
+		dev_err(dev, "failed to register PHY provider\n");
+		return PTR_ERR(provider);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id cygnus_pcie_phy_match_table[] = {
+	{ .compatible = "brcm,cygnus-pcie-phy" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cygnus_pcie_phy_match_table);
+
+static struct platform_driver cygnus_pcie_phy_driver = {
+	.driver = {
+		.name		= "cygnus-pcie-phy",
+		.of_match_table	= cygnus_pcie_phy_match_table,
+	},
+	.probe	= cygnus_pcie_phy_probe,
+};
+module_platform_driver(cygnus_pcie_phy_driver);
+
+MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom Cygnus PCIe PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


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

* [PATCH v2 5/5] ARM: dts: enable PCIe PHY support for Cygnus
  2015-05-22  1:07 [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
                   ` (3 preceding siblings ...)
  2015-05-22  1:07 ` [PATCH v2 4/5] phy: cygnus: pcie: Add Cygnus PCIe PHY support Ray Jui
@ 2015-05-22  1:07 ` Ray Jui
  2015-09-01 21:13 ` [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
  5 siblings, 0 replies; 7+ messages in thread
From: Ray Jui @ 2015-05-22  1:07 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Arnd Bergmann
  Cc: linux-kernel, JD (Jiandong) Zheng, Arun Parameswaran,
	bcm-kernel-feedback-list, Ray Jui

Added MDIO and PCIe PHY device nodes for Cygnus. The PCIe PHY is
referenced by the iProc PCIe device

Signed-off-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Arun Parameswaran <aparames@broadcom.com>
Reviewed-by: JD (Jiandong) Zheng <jdzheng@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 arch/arm/boot/dts/bcm-cygnus.dtsi |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
index 7b52c33..57667a8 100644
--- a/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -106,6 +106,20 @@
 		};
 	};
 
+	mdio_bus: mdio_bus@18002000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "brcm,iproc-mdio";
+		reg = <0x18002000 0x8>;
+		ranges;
+
+		pcie_phy: pcie_phy@0301d0a0 {
+			compatible = "brcm,cygnus-pcie-phy";
+			reg = <0x0301d0a0 0x14>;
+			#phy-cells = <2>;
+		};
+	};
+
 	i2c0: i2c@18008000 {
 		compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c";
 		reg = <0x18008000 0x100>;
@@ -144,6 +158,9 @@
 		ranges = <0x81000000 0 0	  0x28000000 0 0x00010000
 			  0x82000000 0 0x20000000 0x20000000 0 0x04000000>;
 
+		phys = <&pcie_phy 0 5>;
+		phy-names = "pcie-phy";
+
 		status = "disabled";
 	};
 
@@ -165,6 +182,9 @@
 		ranges = <0x81000000 0 0	  0x48000000 0 0x00010000
 			  0x82000000 0 0x40000000 0x40000000 0 0x04000000>;
 
+		phys = <&pcie_phy 1 6>;
+		phy-names = "pcie-phy";
+
 		status = "disabled";
 	};
 
-- 
1.7.9.5


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

* Re: [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support
  2015-05-22  1:07 [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
                   ` (4 preceding siblings ...)
  2015-05-22  1:07 ` [PATCH v2 5/5] ARM: dts: enable PCIe PHY support for Cygnus Ray Jui
@ 2015-09-01 21:13 ` Ray Jui
  5 siblings, 0 replies; 7+ messages in thread
From: Ray Jui @ 2015-09-01 21:13 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Arnd Bergmann
  Cc: linux-kernel, JD (Jiandong) Zheng, Arun Parameswaran,
	bcm-kernel-feedback-list

Hi Arnd,

Please help to advise if the following changes make sense to you. There
does not seem to be a maintainer for drivers/bus/* and Florian mentioned
that you "may" be able to help to pull in changes for ARM SoCs related
changes under drivers/bus/*.

The problem I'm trying to solve:
Some iProc based SoCs (like Cygnus) has an internal MDIO based bus
interface that is used to communicate with various types of Serdes/PHYs
including PCIe, Ethernet, and etc. However, there's only one MDIO
interface per SoC so the access needs to be serialized and protected in
software

The solution:
1. According to convention, Ethernet PHYs should be in drivers/net/phy/*
and PCIe (and other) PHYs should be in drivers/phy/*
2. Kishon suggested putting the low-level MDIO interface/bus driver in
drivers/bus/* which I also think is more proper than leaving it any
where else
3. Both PCIe PHY driver and Ethernet PHY driver call specific iproc
based MDIO API to access their PHYs (e.g., iproc_mdio_write and
iproc_mdio_read).

There are some changes/fixes I need to make to both the MDIO bus driver
and PCIe PHY driver so there will be a v3 of this patchset. But before I
do that, I'd like to cross check with you and make sure the way how I
partition these drivers are acceptable.

Thanks,

Ray

On 5/21/2015 6:07 PM, Ray Jui wrote:
> This patch series adds support for the Cygnus PCIe PHY and support of the
> MDC/MDIO bus interface found in various iProc based of SoCs. The iProc
> MDC/MDIO bus interface can be used by the host processor to communicate with
> various internal Serdes/PHYs including Ethernet, PCIe, USB, etc.
> 
> This patch series is based on Linux v4.1-rc4 and is avaliable in:
> https://github.com/Broadcom/cygnus-linux/tree/cygnus-pcie-phy-v2
> 
> Changes from v1:
>  - Move the MDC/MDIO bus driver from drivers/phy/* to drivers/bus/*
>  - Make the PCIe PHY device node child node of the MDIO bus
>  - Change the PCIe PHY driver to tristate so it can be compiled as a module
>  - Other minor changes
> 
> Ray Jui (5):
>   dt_bindings: Add iProc MDC/MDIO interface binding
>   phy: iproc-mdio: Initial iProc MDC/MDIO support
>   phy: cygnus: pcie: Define DT binding
>   phy: cygnus: pcie: Add Cygnus PCIe PHY support
>   ARM: dts: enable PCIe PHY support for Cygnus
> 
>  .../devicetree/bindings/bus/brcm,iproc-mdio.txt    |   21 ++
>  .../bindings/phy/brcm,cygnus-pcie-phy.txt          |   34 ++
>  arch/arm/boot/dts/bcm-cygnus.dtsi                  |   20 ++
>  drivers/bus/Kconfig                                |   12 +
>  drivers/bus/Makefile                               |    1 +
>  drivers/bus/iproc-mdio-bus.c                       |  255 +++++++++++++++
>  drivers/phy/Kconfig                                |   15 +
>  drivers/phy/Makefile                               |    1 +
>  drivers/phy/phy-cygnus-pcie.c                      |  340 ++++++++++++++++++++
>  include/linux/iproc_mdio_bus.h                     |   22 ++
>  10 files changed, 721 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bus/brcm,iproc-mdio.txt
>  create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-pcie-phy.txt
>  create mode 100644 drivers/bus/iproc-mdio-bus.c
>  create mode 100644 drivers/phy/phy-cygnus-pcie.c
>  create mode 100644 include/linux/iproc_mdio_bus.h
> 

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

end of thread, other threads:[~2015-09-01 21:14 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-22  1:07 [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui
2015-05-22  1:07 ` [PATCH v2 1/5] dt_bindings: Add iProc MDC/MDIO interface binding Ray Jui
2015-05-22  1:07 ` [PATCH v2 2/5] phy: iproc-mdio: Initial iProc MDC/MDIO support Ray Jui
2015-05-22  1:07 ` [PATCH v2 3/5] phy: cygnus: pcie: Define DT binding Ray Jui
2015-05-22  1:07 ` [PATCH v2 4/5] phy: cygnus: pcie: Add Cygnus PCIe PHY support Ray Jui
2015-05-22  1:07 ` [PATCH v2 5/5] ARM: dts: enable PCIe PHY support for Cygnus Ray Jui
2015-09-01 21:13 ` [PATCH v2 0/5] Add iProc MDIO and Cygnus PCIe PHY support Ray Jui

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.