2017-04-28 20:30:06

by Jon Mason

[permalink] [raw]
Subject: [PATCH 0/3] USB3 support for Broadcom NS2 SoC

This patch set contains the USB3 support for Broadcom NS2 SoC. The USB3
PHY is connected through the MDIO interface.

Yendapally Reddy Dhananjaya Reddy (3):
dt-bindings: phy: Add documentation for NS2 USB3 PHY
phy: Add USB3 PHY support for Broadcom NS2 SoC
arm64: dts: ns2: Add USB3 Support

.../devicetree/bindings/phy/brcm,ns2-usb3-phy.txt | 82 +++
arch/arm64/boot/dts/broadcom/ns2-svk.dts | 16 +
arch/arm64/boot/dts/broadcom/ns2-xmc.dts | 8 +
arch/arm64/boot/dts/broadcom/ns2.dtsi | 62 +++
drivers/phy/Kconfig | 9 +
drivers/phy/Makefile | 1 +
drivers/phy/phy-bcm-ns2-usb3.c | 596 +++++++++++++++++++++
7 files changed, 774 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/brcm,ns2-usb3-phy.txt
create mode 100644 drivers/phy/phy-bcm-ns2-usb3.c

--
2.7.4


2017-04-28 20:30:17

by Jon Mason

[permalink] [raw]
Subject: [PATCH 1/3] dt-bindings: phy: Add documentation for NS2 USB3 PHY

From: Yendapally Reddy Dhananjaya Reddy <[email protected]>

Add documentation for USB3 PHY available in NS2 SoC

Signed-off-by: Yendapally Reddy Dhananjaya Reddy <[email protected]>
Signed-off-by: Jon Mason <[email protected]>
---
.../devicetree/bindings/phy/brcm,ns2-usb3-phy.txt | 82 ++++++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/brcm,ns2-usb3-phy.txt

diff --git a/Documentation/devicetree/bindings/phy/brcm,ns2-usb3-phy.txt b/Documentation/devicetree/bindings/phy/brcm,ns2-usb3-phy.txt
new file mode 100644
index 0000000..5bb8d53
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,ns2-usb3-phy.txt
@@ -0,0 +1,82 @@
+Broadcom USB3 dual port phy for Northstar2 SoC
+This is a child bus node of "brcm,mdio-mux-iproc" node.
+
+Required mdio bus properties:
+- reg: MDIO Bus number for the MDIO interface
+- #address-cells: must be 1
+- #size-cells: must be 0
+
+Required PHY properties:
+- compatible: should be "brcm,ns2-usb3-phy"
+- reg: Phy address in the MDIO interface
+- usb3-ctrl-syscon: handler of syscon node defining physical address
+ of usb3 control register.
+- usb3-phy-cfg-syscon: handler of syscon node defining physical base
+ address and length of usb3 phy config region.
+- usb3-rst-ctrl-syscon: handler of syscon node defining physical base
+ address and length of idm reset control of two ports.
+- #phy-cells: must be 0
+- #address-cells: must be 1
+- #size-cells: must be 0
+
+Sub-nodes:
+ Each port's PHY should be represented as a sub-node.
+
+Sub-nodes required properties:
+ - reg: the PHY number
+ - phy-cells: from the generic PHY bindings, must be 0
+
+Required usb3 control properties:
+- compatible: should be "brcm,ns2-usb3-ctrl"
+- reg: offset and length of the control registers
+
+Required usb3 phy config properties:
+- compatible: should be "brcm,ns2-usb3-phy-cfg"
+- reg: offset and length of the phy config registers
+
+Required usb3 reset control properties:
+- compatible: should be "brcm,ns2-usb3-rst-ctrl"
+- reg: offset and length of the reset control registers
+
+Example:
+
+mdio@1 {
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb3phy: usb3phy@0 {
+ compatible = "brcm,ns2-usb3-phy";
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ usb3-ctrl-syscon = <&usb3_ctrl>;
+ usb3-phy-cfg-syscon = <&usb3_phy_cfg>;
+ usb3-rst-ctrl-syscon = <&usb3_rst_ctrl>;
+
+ usb3phy0: usbphy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ usb3phy1: usbphy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
+};
+
+usb3_ctrl: syscon@6501d144 {
+ compatible = "brcm,ns2-usb3-ctrl", "syscon";
+ reg = <0x6501d144 0x4>;
+};
+
+usb3_phy_cfg: syscon@66000910 {
+ compatible = "brcm,ns2-usb3-phy-cfg", "syscon";
+ reg = <0x66000910 0x14>;
+};
+
+usb3_rst_ctrl: syscon@67000800 {
+ compatible = "brcm,ns2-usb3-rst-ctrl", "syscon";
+ reg = <0x67000800 0x1808>;
+};
--
2.7.4

2017-04-28 20:30:41

by Jon Mason

[permalink] [raw]
Subject: [PATCH 2/3] phy: Add USB3 PHY support for Broadcom NS2 SoC

From: Yendapally Reddy Dhananjaya Reddy <[email protected]>

This patch adds support for Broadcom NS2 USB3 PHY

Signed-off-by: Yendapally Reddy Dhananjaya Reddy <[email protected]>
Signed-off-by: Jon Mason <[email protected]>
---
drivers/phy/Kconfig | 9 +
drivers/phy/Makefile | 1 +
drivers/phy/phy-bcm-ns2-usb3.c | 596 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 606 insertions(+)
create mode 100644 drivers/phy/phy-bcm-ns2-usb3.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index dc5277a..c86f47c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -498,6 +498,15 @@ config PHY_NS2_PCIE
Enable this to support the Broadcom Northstar2 PCIe PHY.
If unsure, say N.

+config PHY_NS2_USB3
+ tristate "Broadcom NorthStar2 USB3 PHY driver"
+ depends on OF && (ARCH_BCM_IPROC || COMPILE_TEST)
+ select GENERIC_PHY
+ default ARCH_BCM_IPROC
+ help
+ Enable this to support the Broadcom Northstar2 USB3 PHY.
+ If unsure, say N.
+
config PHY_MESON8B_USB2
tristate "Meson8b and GXBB USB2 PHY driver"
default ARCH_MESON
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index e7b0feb..8ad8920 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -61,5 +61,6 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
+obj-$(CONFIG_PHY_NS2_USB3) += phy-bcm-ns2-usb3.o
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
obj-$(CONFIG_PHY_NSP_USB3) += phy-bcm-nsp-usb3.o
diff --git a/drivers/phy/phy-bcm-ns2-usb3.c b/drivers/phy/phy-bcm-ns2-usb3.c
new file mode 100644
index 0000000..203f509
--- /dev/null
+++ b/drivers/phy/phy-bcm-ns2-usb3.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+
+#define NS2_USB3_PHY_MAX 0x02
+
+#define NS2_USB3_PHY_CONFIG_CTRL_REG 0x00
+#define NS2_USB3_PHY_CONFIG_CTRL_MASK (BIT(3) | BIT(4) | BIT(5))
+#define NS2_USB3_PHY_CONFIG_CTRL_PLL_SEQ_START BIT(6)
+
+#define NS2_USB3_PHY_P0CTL_REG 0x04
+#define NS2_USB3_PHY_P1CTL_REG 0x08
+#define NS2_USB3_PHY_PXCTL_I_BIT BIT(1)
+
+#define NS2_USB3_PHY_MISC_STATUS_REG 0x10
+
+#define NS2_IDM_RST_CTRL_P0_OFFSET 0x3f8
+#define NS2_IDM_RST_CTRL_P1_OFFSET 0x13f8
+#define NS2_IDM_RESET_CONTROL_BIT BIT(0)
+
+#define NS2_IDM_IO_CTRL_P0_OFFSET 0x0
+#define NS2_IDM_IO_CTRL_P1_OFFSET 0x1000
+/* Bit 23 for PPC Polarity, Bit 24 for PPC NANDNOR select */
+#define NS2_IDM_IO_CTRL_PPC_CFG (BIT(23) | BIT(24))
+
+#define NS2_PHY_RESET_BIT BIT(5)
+#define NS2_PHY_PLL_RESET_BIT BIT(6)
+
+/* NS2 USB3 MDIO */
+#define NS2_USB3_MDIO_PLL30_ADDR 0x8000
+#define NS2_USB3_MDIO_BLK_ACCESS 0x1F
+#define NS2_USB3_MDIO_PLL30_ANAPLL_CTRL 0x14
+#define NS2_USB3_MDIO_PLL30_ANAPLL_CTRL_VAL 0x23
+#define NS2_USB3_MDIO_PLL30_GEN_PLL 0xF
+#define NS2_USB3_MDIO_PLL30_GEN_PLL_PCLK_SEL BIT(11)
+#define NS2_USB3_MDIO_P0_AFE30_ADDR 0x8080
+#define NS2_USB3_MDIO_P1_AFE30_ADDR 0x9080
+#define NS2_USB3_MDIO_AFE30_RX_SIG_DETECT 0x5
+#define NS2_USB3_MDIO_AFE30_RX_SIG_DETECT_VAL 0xAC0D
+
+#define NS2_USB3_MDIO_P0_PIPE_BLK_ADDR 0x8060
+#define NS2_USB3_MDIO_P1_PIPE_BLK_ADDR 0x9060
+#define NS2_USB3_MDIO_PIPE_BLK_REG_1_OFFSET 0x1
+#define NS2_USB3_MDIO_PIPE_BLK_REG_1_VAL 0x207
+
+#define NS2_USB3_MDIO_P0_AEQ_BLK_ADDR 0x80E0
+#define NS2_USB3_MDIO_P1_AEQ_BLK_ADDR 0x90E0
+#define NS2_USB3_MDIO_AEQ_BLK_REG_1_OFFSET 0x1
+#define NS2_USB3_MDIO_AEQ_BLK_REG_1_VAL 0x3000
+
+/* USB3 Histogram Programming */
+#define NS2_USB3_IRAADR_OFFSET 0x198
+#define NS2_USB3_IRADAT_OFFSET 0x19c
+#define USB3_HISTOGRAM_OFFSET_VAL 0xA200
+#define USB3_BYPASS_VBUS_INPUTS BIT(2)
+#define USB3_OVERRIDE_VBU_PRESENT BIT(3)
+#define USB3_OVERRIDE_CURRENT_MASK (~(BIT(4)))
+#define NS2_USB3_MDIO_RESET_BIT (BIT(12))
+
+enum ns2_phy_block {
+ PHY_RESET,
+ PHY_PLL_RESET,
+ PHY_SOFT_RESET,
+ PHY_PIPE_RESET,
+ PHY_REF_CLOCK,
+ PHY_PLL_SEQ_START,
+ PHY_PLL_STATUS,
+ PHY_VBUS_PPC,
+};
+
+enum ns2_reg_base {
+ NS2_USB3_CTRL = 1,
+ NS2_USB3_PHY_CFG,
+ NS2_USB3_RST_CTRL,
+ NS2_USB3_REG_BASE_MAX
+};
+
+struct ns2_usb3_phy {
+ void __iomem *reg_base[NS2_USB3_REG_BASE_MAX];
+ struct ns2_usb3_phy_master *mphy;
+ struct phy *phy;
+ int port_no;
+};
+
+struct ns2_usb3_phy_master {
+ struct ns2_usb3_phy iphys[NS2_USB3_PHY_MAX];
+ struct mdio_device *mdiodev;
+ struct mutex phy_mutex;
+ int init_count; /* PHY is dual port phy, so init once*/
+};
+
+static int iproc_ns2_phy_action(struct ns2_usb3_phy *iphy,
+ enum ns2_phy_block block, bool assert)
+{
+ void __iomem *addr;
+ u32 data, count;
+ u32 offset = 0;
+ int ret = 0;
+
+ switch (block) {
+ case PHY_RESET:
+ addr = iphy->reg_base[NS2_USB3_CTRL];
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data &= ~NS2_PHY_RESET_BIT;
+ else
+ data |= NS2_PHY_RESET_BIT;
+
+ ret = regmap_write(addr, offset, data);
+ break;
+
+ case PHY_PLL_RESET:
+ addr = iphy->reg_base[NS2_USB3_CTRL];
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data &= ~NS2_PHY_PLL_RESET_BIT;
+ else
+ data |= NS2_PHY_PLL_RESET_BIT;
+
+ ret = regmap_write(addr, offset, data);
+ break;
+
+ case PHY_SOFT_RESET:
+ addr = iphy->reg_base[NS2_USB3_PHY_CFG];
+ offset = NS2_USB3_PHY_P0CTL_REG;
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data &= ~NS2_USB3_PHY_PXCTL_I_BIT;
+ else
+ data |= NS2_USB3_PHY_PXCTL_I_BIT;
+
+ ret = regmap_write(addr, offset, data);
+ if (ret != 0)
+ return ret;
+
+ offset = NS2_USB3_PHY_P1CTL_REG;
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data &= ~NS2_USB3_PHY_PXCTL_I_BIT;
+ else
+ data |= NS2_USB3_PHY_PXCTL_I_BIT;
+
+ ret = regmap_write(addr, offset, data);
+ break;
+
+ case PHY_PIPE_RESET:
+ addr = iphy->reg_base[NS2_USB3_RST_CTRL];
+ offset = NS2_IDM_RST_CTRL_P0_OFFSET;
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data |= NS2_IDM_RESET_CONTROL_BIT;
+ else
+ data &= ~NS2_IDM_RESET_CONTROL_BIT;
+
+ ret = regmap_write(addr, offset, data);
+ if (ret != 0)
+ return ret;
+
+ offset = NS2_IDM_RST_CTRL_P1_OFFSET;
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data |= NS2_IDM_RESET_CONTROL_BIT;
+ else
+ data &= ~NS2_IDM_RESET_CONTROL_BIT;
+
+ ret = regmap_write(addr, offset, data);
+ break;
+
+ case PHY_VBUS_PPC:
+ addr = iphy->reg_base[NS2_USB3_RST_CTRL];
+ offset = NS2_IDM_IO_CTRL_P0_OFFSET;
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data |= NS2_IDM_IO_CTRL_PPC_CFG;
+ else
+ data &= ~NS2_IDM_IO_CTRL_PPC_CFG;
+
+ ret = regmap_write(addr, offset, data);
+ if (ret != 0)
+ return ret;
+
+ offset = NS2_IDM_IO_CTRL_P1_OFFSET;
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (assert)
+ data |= NS2_IDM_IO_CTRL_PPC_CFG;
+ else
+ data &= ~NS2_IDM_IO_CTRL_PPC_CFG;
+
+ ret = regmap_write(addr, offset, data);
+ break;
+
+ case PHY_REF_CLOCK:
+ addr = iphy->reg_base[NS2_USB3_PHY_CFG];
+ offset = NS2_USB3_PHY_CONFIG_CTRL_REG;
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ data &= ~NS2_USB3_PHY_CONFIG_CTRL_MASK;
+
+ ret = regmap_write(addr, offset, data);
+ break;
+
+ case PHY_PLL_SEQ_START:
+ addr = iphy->reg_base[NS2_USB3_PHY_CFG];
+ offset = NS2_USB3_PHY_CONFIG_CTRL_REG;
+
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ data |= NS2_USB3_PHY_CONFIG_CTRL_PLL_SEQ_START;
+
+ ret = regmap_write(addr, offset, data);
+ break;
+
+ case PHY_PLL_STATUS:
+ count = 2000;
+ addr = iphy->reg_base[NS2_USB3_PHY_CFG];
+ offset = NS2_USB3_PHY_MISC_STATUS_REG;
+
+ do {
+ udelay(1);
+ ret = regmap_read(addr, offset, &data);
+ if (ret != 0)
+ return ret;
+
+ if (data == 1)
+ break;
+ } while (--count);
+
+ if (!count)
+ ret = -ETIMEDOUT;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ns2_usb3_phy_exit(struct phy *phy)
+{
+ struct ns2_usb3_phy *iphy = phy_get_drvdata(phy);
+ int rc = 0;
+
+ mutex_lock(&iphy->mphy->phy_mutex);
+
+ if (iphy->mphy->init_count <= 0) {
+ mutex_unlock(&iphy->mphy->phy_mutex);
+ return 0;
+ } else if (iphy->mphy->init_count == 1) {
+ /* Only put in to reset for last port to exit */
+ rc = iproc_ns2_phy_action(iphy, PHY_PLL_RESET, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_SOFT_RESET, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_RESET, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_PIPE_RESET, true);
+ if (rc)
+ goto out;
+ }
+
+out:
+ iphy->mphy->init_count--;
+ mutex_unlock(&iphy->mphy->phy_mutex);
+
+ return rc;
+}
+
+static int ns2_usb3_phy_init(struct phy *phy)
+{
+ struct ns2_usb3_phy *iphy = phy_get_drvdata(phy);
+ u16 addr;
+ u16 reg_val;
+ int rc;
+
+ mutex_lock(&iphy->mphy->phy_mutex);
+
+ if (iphy->mphy->init_count) {
+ /* Use count to identify last port to call phy_exit. */
+ iphy->mphy->init_count++;
+ mutex_unlock(&iphy->mphy->phy_mutex);
+ return 0;
+ }
+
+ rc = iproc_ns2_phy_action(iphy, PHY_RESET, false);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_SOFT_RESET, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_PIPE_RESET, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_REF_CLOCK, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_PLL_RESET, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_RESET, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_RESET, false);
+ if (rc)
+ goto out;
+
+ /* PLL programming */
+ /* PHY PLL30 Block */
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_BLK_ACCESS,
+ NS2_USB3_MDIO_PLL30_ADDR);
+ if (rc)
+ goto out;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_PLL30_ANAPLL_CTRL,
+ NS2_USB3_MDIO_PLL30_ANAPLL_CTRL_VAL);
+ if (rc)
+ goto out;
+
+ reg_val = (u16) mdiobus_read(iphy->mphy->mdiodev->bus,
+ iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_PLL30_GEN_PLL);
+ reg_val |= NS2_USB3_MDIO_PLL30_GEN_PLL_PCLK_SEL;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_PLL30_GEN_PLL, reg_val);
+ if (rc)
+ goto out;
+
+ /* PHY AFE30 Block */
+ addr = NS2_USB3_MDIO_P0_AFE30_ADDR;
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_BLK_ACCESS, addr);
+ if (rc)
+ goto out;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_AFE30_RX_SIG_DETECT,
+ NS2_USB3_MDIO_AFE30_RX_SIG_DETECT_VAL);
+ if (rc)
+ goto out;
+
+ addr = NS2_USB3_MDIO_P1_AFE30_ADDR;
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_BLK_ACCESS, addr);
+ if (rc)
+ goto out;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_AFE30_RX_SIG_DETECT,
+ NS2_USB3_MDIO_AFE30_RX_SIG_DETECT_VAL);
+ if (rc)
+ goto out;
+
+ /* PHY PIPE Block */
+ addr = NS2_USB3_MDIO_P0_PIPE_BLK_ADDR;
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_BLK_ACCESS, addr);
+ if (rc)
+ goto out;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_PIPE_BLK_REG_1_OFFSET,
+ NS2_USB3_MDIO_PIPE_BLK_REG_1_VAL);
+ if (rc)
+ goto out;
+
+ addr = NS2_USB3_MDIO_P1_PIPE_BLK_ADDR;
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_BLK_ACCESS, addr);
+ if (rc)
+ goto out;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_PIPE_BLK_REG_1_OFFSET,
+ NS2_USB3_MDIO_PIPE_BLK_REG_1_VAL);
+ if (rc)
+ goto out;
+
+ /* AEQ Block */
+ addr = NS2_USB3_MDIO_P0_AEQ_BLK_ADDR;
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_BLK_ACCESS, addr);
+ if (rc)
+ goto out;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_AEQ_BLK_REG_1_OFFSET,
+ NS2_USB3_MDIO_AEQ_BLK_REG_1_VAL);
+ if (rc)
+ goto out;
+
+ /* PHY PORT_1 */
+ addr = NS2_USB3_MDIO_P1_AEQ_BLK_ADDR;
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_BLK_ACCESS, addr);
+ if (rc)
+ goto out;
+
+ rc = mdiobus_write(iphy->mphy->mdiodev->bus, iphy->mphy->mdiodev->addr,
+ NS2_USB3_MDIO_AEQ_BLK_REG_1_OFFSET,
+ NS2_USB3_MDIO_AEQ_BLK_REG_1_VAL);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_PLL_SEQ_START, true);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_PIPE_RESET, false);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_SOFT_RESET, false);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_PLL_RESET, false);
+ if (rc)
+ goto out;
+
+ rc = iproc_ns2_phy_action(iphy, PHY_PLL_STATUS, true);
+ if (rc)
+ goto out;
+
+ /* Set USB3H VBUS PPC Polarity and NandNor select */
+ rc = iproc_ns2_phy_action(iphy, PHY_VBUS_PPC, true);
+
+out:
+ iphy->mphy->init_count++;
+ mutex_unlock(&iphy->mphy->phy_mutex);
+
+ return rc;
+}
+
+static struct phy_ops ns2_usb3_phy_ops = {
+ .init = ns2_usb3_phy_init,
+ .exit = ns2_usb3_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static int ns2_usb3_phy_probe(struct mdio_device *mdiodev)
+{
+ struct device *dev = &mdiodev->dev;
+ struct device_node *dn = dev->of_node, *child;
+ struct ns2_usb3_phy_master *mphy;
+ struct phy_provider *provider;
+ int cnt;
+
+ mphy = devm_kzalloc(dev, sizeof(*mphy), GFP_KERNEL);
+ if (!mphy)
+ return -ENOMEM;
+ mphy->mdiodev = mdiodev;
+ mutex_init(&mphy->phy_mutex);
+ mphy->init_count = 0;
+
+ cnt = 0;
+ for_each_available_child_of_node(dn, child) {
+ struct ns2_usb3_phy *iphy;
+ unsigned int val;
+ struct regmap *io;
+
+ iphy = &mphy->iphys[cnt];
+ if (of_property_read_u32(child, "reg", &val)) {
+ dev_err(dev, "missing reg property in node %s\n",
+ child->name);
+ return -EINVAL;
+ }
+ iphy->port_no = val;
+ iphy->mphy = mphy;
+
+ io = syscon_regmap_lookup_by_phandle(dn, "usb3-ctrl-syscon");
+ if (IS_ERR(io))
+ return PTR_ERR(io);
+ iphy->reg_base[NS2_USB3_CTRL] = io;
+
+ io = syscon_regmap_lookup_by_phandle(dn, "usb3-phy-cfg-syscon");
+ if (IS_ERR(io))
+ return PTR_ERR(io);
+ iphy->reg_base[NS2_USB3_PHY_CFG] = io;
+
+ io = syscon_regmap_lookup_by_phandle(dn,
+ "usb3-rst-ctrl-syscon");
+ if (IS_ERR(io))
+ return PTR_ERR(io);
+ iphy->reg_base[NS2_USB3_RST_CTRL] = io;
+
+ iphy->phy = devm_phy_create(dev, child, &ns2_usb3_phy_ops);
+ if (IS_ERR(iphy->phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(iphy->phy);
+ }
+
+ phy_set_drvdata(iphy->phy, iphy);
+ cnt++;
+ }
+
+ dev_set_drvdata(dev, mphy);
+ provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(provider)) {
+ dev_err(dev, "could not register PHY provider\n");
+ return PTR_ERR(provider);
+ }
+
+ dev_info(dev, "registered %d phy(s)\n", cnt);
+ return 0;
+}
+
+static const struct of_device_id ns2_usb3_phy_of_match[] = {
+ {.compatible = "brcm,ns2-usb3-phy",},
+ { /* sentinel */ }
+};
+
+static struct mdio_driver ns2_usb3_phy_driver = {
+ .mdiodrv = {
+ .driver = {
+ .name = "ns2-usb3-phy",
+ .of_match_table = ns2_usb3_phy_of_match,
+ },
+ },
+ .probe = ns2_usb3_phy_probe,
+};
+mdio_module_driver(ns2_usb3_phy_driver);
+
+MODULE_DESCRIPTION("Broadcom NS2 USB3 PHY driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Broadcom");
--
2.7.4

2017-04-28 20:30:32

by Jon Mason

[permalink] [raw]
Subject: [PATCH 3/3] arm64: dts: ns2: Add USB3 Support

From: Yendapally Reddy Dhananjaya Reddy <[email protected]>

Add USB3 support to the Northstar2 Device tree files

Signed-off-by: Yendapally Reddy Dhananjaya Reddy <[email protected]>
Signed-off-by: Jon Mason <[email protected]>
---
arch/arm64/boot/dts/broadcom/ns2-svk.dts | 16 +++++++++
arch/arm64/boot/dts/broadcom/ns2-xmc.dts | 8 +++++
arch/arm64/boot/dts/broadcom/ns2.dtsi | 62 ++++++++++++++++++++++++++++++++
3 files changed, 86 insertions(+)

diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
index ec19fbf..7cd2ef7 100644
--- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts
+++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
@@ -234,3 +234,19 @@
};
};
};
+
+&usb3_phy0 {
+ status = "okay";
+};
+
+&usb3_phy1 {
+ status = "okay";
+};
+
+&xhci0 {
+ status = "okay";
+};
+
+&xhci1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/ns2-xmc.dts b/arch/arm64/boot/dts/broadcom/ns2-xmc.dts
index ab4ae1a..8e8feb7 100644
--- a/arch/arm64/boot/dts/broadcom/ns2-xmc.dts
+++ b/arch/arm64/boot/dts/broadcom/ns2-xmc.dts
@@ -189,3 +189,11 @@
&uart3 {
status = "okay";
};
+
+&usb3_phy0 {
+ status = "okay";
+};
+
+&xhci0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi
index 35a309a..2360ff5 100644
--- a/arch/arm64/boot/dts/broadcom/ns2.dtsi
+++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi
@@ -343,6 +343,11 @@
<0x660009b0 0x40>;
};

+ usb3_ctrl: syscon@6501d144 {
+ compatible = "brcm,ns2-usb3-ctrl", "syscon";
+ reg = <0x6501d144 0x4>;
+ };
+
gpio_aon: gpio@65024800 {
compatible = "brcm,iproc-gpio";
reg = <0x65024800 0x50>,
@@ -460,6 +465,11 @@
};
};

+ usb3_phy_cfg: syscon@66000910 {
+ compatible = "brcm,ns2-usb3-phy-cfg", "syscon";
+ reg = <0x66000910 0x14>;
+ };
+
pwm: pwm@66010000 {
compatible = "brcm,iproc-pwm";
reg = <0x66010000 0x28>;
@@ -487,6 +497,34 @@
};
};

+ mdio@1 {
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usb3_phy: usb3_phy@0 {
+ compatible = "brcm,ns2-usb3-phy";
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ usb3-ctrl-syscon = <&usb3_ctrl>;
+ usb3-phy-cfg-syscon = <&usb3_phy_cfg>;
+ usb3-rst-ctrl-syscon = <&usb3_rst_ctrl>;
+
+ usb3_phy0: usb3_phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+
+ usb3_phy1: usb_phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+ };
+ };
+
mdio@7 {
reg = <0x7>;
#address-cells = <1>;
@@ -652,6 +690,26 @@
reg = <0x66220000 0x28>;
};

+ xhci0: usb@66300000 {
+ compatible = "generic-xhci";
+ reg = <0x66300000 0x1000>;
+ interrupts = <GIC_SPI 429 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb3_phy0>;
+ phy-names = "usb";
+ dma-coherent;
+ status = "disabled";
+ };
+
+ xhci1: usb@66310000 {
+ compatible = "generic-xhci";
+ reg = <0x66310000 0x1000>;
+ interrupts = <GIC_SPI 433 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb3_phy1>;
+ phy-names = "usb";
+ dma-coherent;
+ status = "disabled";
+ };
+
sata_phy: sata_phy@663f0100 {
compatible = "brcm,iproc-ns2-sata-phy";
reg = <0x663f0100 0x1f00>,
@@ -747,5 +805,9 @@
#size-cells = <0>;
};

+ usb3_rst_ctrl: syscon@67000408 {
+ compatible = "brcm,ns2-usb3-rst-ctrl", "syscon";
+ reg = <0x67000408 0x1808>;
+ };
};
};
--
2.7.4