All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] Add Rockchip new PCIe controller and combo phy support
@ 2020-01-14  7:22 ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci, devicetree, William Wu, Simon Xue,
	linux-rockchip, Shawn Lin


Rockchip's new PCIe controller is based on DesignWare IP and the
combo phy is shard by PCIe and USB3.0 controller. This series adds
both of controller and phy drivers found on Rockchip RV1808 platform.



Shawn Lin (3):
  dt-bindings: add binding for Rockchip combo phy using an Innosilicon
    IP
  PCI: dwc: Skip allocating own MSI domain if using external MSI domain
  MAINTAINERS: Update PCIe drivers for Rockchip

Simon Xue (2):
  dt-bindings: rockchip: Add DesignWare based PCIe controller
  PCI: rockchip: add DesignWare based PCIe controller

William Wu (1):
  phy/rockchip: inno-combophy: Add initial support

 .../devicetree/bindings/pci/rockchip-dw-pcie.yaml  |  132 +++
 .../bindings/phy/rockchip,inno-combophy.yaml       |   84 ++
 MAINTAINERS                                        |    4 +-
 drivers/pci/controller/dwc/Kconfig                 |    9 +
 drivers/pci/controller/dwc/Makefile                |    1 +
 drivers/pci/controller/dwc/pcie-designware-host.c  |   10 +-
 drivers/pci/controller/dwc/pcie-designware.h       |    1 +
 drivers/pci/controller/dwc/pcie-dw-rockchip.c      |  441 ++++++++
 drivers/phy/rockchip/Kconfig                       |    8 +
 drivers/phy/rockchip/Makefile                      |    1 +
 drivers/phy/rockchip/phy-rockchip-inno-combphy.c   | 1056 ++++++++++++++++++++
 11 files changed, 1745 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
 create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
 create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c
 create mode 100644 drivers/phy/rockchip/phy-rockchip-inno-combphy.c

-- 
1.9.1




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

* [PATCH 0/6] Add Rockchip new PCIe controller and combo phy support
@ 2020-01-14  7:22 ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	Shawn Lin, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu


Rockchip's new PCIe controller is based on DesignWare IP and the
combo phy is shard by PCIe and USB3.0 controller. This series adds
both of controller and phy drivers found on Rockchip RV1808 platform.



Shawn Lin (3):
  dt-bindings: add binding for Rockchip combo phy using an Innosilicon
    IP
  PCI: dwc: Skip allocating own MSI domain if using external MSI domain
  MAINTAINERS: Update PCIe drivers for Rockchip

Simon Xue (2):
  dt-bindings: rockchip: Add DesignWare based PCIe controller
  PCI: rockchip: add DesignWare based PCIe controller

William Wu (1):
  phy/rockchip: inno-combophy: Add initial support

 .../devicetree/bindings/pci/rockchip-dw-pcie.yaml  |  132 +++
 .../bindings/phy/rockchip,inno-combophy.yaml       |   84 ++
 MAINTAINERS                                        |    4 +-
 drivers/pci/controller/dwc/Kconfig                 |    9 +
 drivers/pci/controller/dwc/Makefile                |    1 +
 drivers/pci/controller/dwc/pcie-designware-host.c  |   10 +-
 drivers/pci/controller/dwc/pcie-designware.h       |    1 +
 drivers/pci/controller/dwc/pcie-dw-rockchip.c      |  441 ++++++++
 drivers/phy/rockchip/Kconfig                       |    8 +
 drivers/phy/rockchip/Makefile                      |    1 +
 drivers/phy/rockchip/phy-rockchip-inno-combphy.c   | 1056 ++++++++++++++++++++
 11 files changed, 1745 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
 create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
 create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c
 create mode 100644 drivers/phy/rockchip/phy-rockchip-inno-combphy.c

-- 
1.9.1

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

* [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci, devicetree, William Wu, Simon Xue,
	linux-rockchip, Shawn Lin

This IP could supports USB3.0 and PCIe.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>

---

 .../bindings/phy/rockchip,inno-combophy.yaml       | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml

diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
new file mode 100644
index 0000000..d647ab3
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/rockchip,inno-combophy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip USB3.0/PCI-e combo phy
+
+maintainers:
+        - Shawn Lin <shawn.lin@rock-chips.com>
+        - William Wu <william.wu@rock-chips.com>
+
+properties:
+  "#phy-cells":
+    const: 1
+
+  compatible:
+    enum:
+      - rockchip,rk1808-combphy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: PLL reference clock
+
+  clock-names:
+    items:
+      - const: refclk
+
+  resets:
+    items:
+      - description: OTG unit reset line
+      - description: POR unit reset line
+      - description: APB interface reset line
+      - description: PIPE unit reset line
+
+  reset-names:
+    items:
+      - const: otg-rst
+      - const: combphy-por
+      - const: combphy-apb
+      - const: combphy-pipe
+
+  rockchip,combphygrf:
+    items:
+      - description: The grf for COMBPHY configuration and state registers.
+
+required:
+  - "#phy-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - rockchip,combphygrf
+
+additionalProperties: false
+
+examples:
+  - |
+    combphy_grf: syscon@fe018000 {
+        compatible = "rockchip,usb3phy-grf", "syscon";
+        reg = <0x0 0xfe018000 0x0 0x8000>;
+    };
+
+    combphy: phy@ff380000 {
+        compatible = "rockchip,rk1808-combphy";
+        reg = <0x0 0xff380000 0x0 0x10000>;
+        #phy-cells = <1>;
+        clocks = <&cru SCLK_PCIEPHY_REF>;
+        clock-names = "refclk";
+        assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
+        assigned-clock-rates = <25000000>;
+        resets = <&cru SRST_USB3_OTG_A>, <&cru SRST_PCIEPHY_POR>,
+                 <&cru SRST_PCIEPHY_P>, <&cru SRST_PCIEPHY_PIPE>;
+        reset-names = "otg-rst", "combphy-por",
+                      "combphy-apb", "combphy-pipe";
+        rockchip,combphygrf = <&combphy_grf>;
+    };
+
+...
-- 
1.9.1




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

* [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	Shawn Lin, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu

This IP could supports USB3.0 and PCIe.

Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

---

 .../bindings/phy/rockchip,inno-combophy.yaml       | 84 ++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml

diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
new file mode 100644
index 0000000..d647ab3
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/rockchip,inno-combophy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip USB3.0/PCI-e combo phy
+
+maintainers:
+        - Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+        - William Wu <william.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+
+properties:
+  "#phy-cells":
+    const: 1
+
+  compatible:
+    enum:
+      - rockchip,rk1808-combphy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: PLL reference clock
+
+  clock-names:
+    items:
+      - const: refclk
+
+  resets:
+    items:
+      - description: OTG unit reset line
+      - description: POR unit reset line
+      - description: APB interface reset line
+      - description: PIPE unit reset line
+
+  reset-names:
+    items:
+      - const: otg-rst
+      - const: combphy-por
+      - const: combphy-apb
+      - const: combphy-pipe
+
+  rockchip,combphygrf:
+    items:
+      - description: The grf for COMBPHY configuration and state registers.
+
+required:
+  - "#phy-cells"
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - rockchip,combphygrf
+
+additionalProperties: false
+
+examples:
+  - |
+    combphy_grf: syscon@fe018000 {
+        compatible = "rockchip,usb3phy-grf", "syscon";
+        reg = <0x0 0xfe018000 0x0 0x8000>;
+    };
+
+    combphy: phy@ff380000 {
+        compatible = "rockchip,rk1808-combphy";
+        reg = <0x0 0xff380000 0x0 0x10000>;
+        #phy-cells = <1>;
+        clocks = <&cru SCLK_PCIEPHY_REF>;
+        clock-names = "refclk";
+        assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
+        assigned-clock-rates = <25000000>;
+        resets = <&cru SRST_USB3_OTG_A>, <&cru SRST_PCIEPHY_POR>,
+                 <&cru SRST_PCIEPHY_P>, <&cru SRST_PCIEPHY_PIPE>;
+        reset-names = "otg-rst", "combphy-por",
+                      "combphy-apb", "combphy-pipe";
+        rockchip,combphygrf = <&combphy_grf>;
+    };
+
+...
-- 
1.9.1

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

* [PATCH 2/6] phy/rockchip: inno-combophy: Add initial support
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci, devicetree, William Wu, Simon Xue,
	linux-rockchip, Shawn Lin

From: William Wu <william.wu@rock-chips.com>

Add initial support for inno-combophy driver which supports
USB3.0 host/device/otg mode as well as PCIe EP/RC mode.

Signed-off-by: William Wu <william.wu@rock-chips.com>
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

 drivers/phy/rockchip/Kconfig                     |    8 +
 drivers/phy/rockchip/Makefile                    |    1 +
 drivers/phy/rockchip/phy-rockchip-inno-combphy.c | 1056 ++++++++++++++++++++++
 3 files changed, 1065 insertions(+)
 create mode 100644 drivers/phy/rockchip/phy-rockchip-inno-combphy.c

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 0824b9d..267306a 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -16,6 +16,14 @@ config PHY_ROCKCHIP_EMMC
 	help
 	  Enable this to support the Rockchip EMMC PHY.
 
+config PHY_ROCKCHIP_INNO_COMBPHY
+	tristate "Rockchip INNO USB 3.0 and PCIe COMBPHY Driver"
+	depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST
+	select GENERIC_PHY
+	help
+	  Enable this to support the Rockchip SoCs COMBPHY.
+	  If unsure, say N.
+
 config PHY_ROCKCHIP_INNO_HDMI
 	tristate "Rockchip INNO HDMI PHY Driver"
 	depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile
index 9f59a81..6813b95 100644
--- a/drivers/phy/rockchip/Makefile
+++ b/drivers/phy/rockchip/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC)		+= phy-rockchip-emmc.o
+obj-$(CONFIG_PHY_ROCKCHIP_INNO_COMBPHY)	+= phy-rockchip-inno-combphy.o
 obj-$(CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY)	+= phy-rockchip-inno-dsidphy.o
 obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI)	+= phy-rockchip-inno-hdmi.o
 obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2)	+= phy-rockchip-inno-usb2.o
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-combphy.c b/drivers/phy/rockchip/phy-rockchip-inno-combphy.c
new file mode 100644
index 0000000..4656ecc
--- /dev/null
+++ b/drivers/phy/rockchip/phy-rockchip-inno-combphy.c
@@ -0,0 +1,1056 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip USB3.0 and PCIE COMBPHY with Innosilicon IP block driver
+ *
+ * Copyright (C) 2018 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <dt-bindings/phy/phy.h>
+
+#define BIT_WRITEABLE_SHIFT	16
+
+struct rockchip_combphy_priv;
+
+enum rockchip_combphy_rst {
+	OTG_RSTN	= 0,
+	PHY_POR_RSTN	= 1,
+	PHY_APB_RSTN	= 2,
+	PHY_PIPE_RSTN	= 3,
+	PHY_GRF_P_RSTN  = 4,
+	PHY_RESET_MAX	= 5,
+};
+
+struct combphy_reg {
+	u32	offset;
+	u32	bitend;
+	u32	bitstart;
+	u32	disable;
+	u32	enable;
+};
+
+struct rockchip_combphy_grfcfg {
+	struct combphy_reg	pipe_l1_sel;
+	struct combphy_reg	pipe_l1_set;
+	struct combphy_reg	pipe_l1pd_sel;
+	struct combphy_reg	pipe_l1pd_p3;
+	struct combphy_reg	pipe_l0pd_sel;
+	struct combphy_reg	pipe_l0pd_p3;
+	struct combphy_reg	pipe_clk_sel;
+	struct combphy_reg	pipe_clk_set;
+	struct combphy_reg	pipe_rate_sel;
+	struct combphy_reg	pipe_rate_set;
+	struct combphy_reg	pipe_mode_sel;
+	struct combphy_reg	pipe_mode_set;
+	struct combphy_reg	pipe_txrx_sel;
+	struct combphy_reg	pipe_txrx_set;
+	struct combphy_reg	pipe_width_sel;
+	struct combphy_reg	pipe_width_set;
+	struct combphy_reg	pipe_usb3_sel;
+	struct combphy_reg	pipe_pll_lock;
+	struct combphy_reg	pipe_status_l0;
+	struct combphy_reg	pipe_l0rxterm_sel;
+	struct combphy_reg	pipe_l1rxterm_sel;
+	struct combphy_reg	pipe_l0rxterm_set;
+	struct combphy_reg	pipe_l1rxterm_set;
+	struct combphy_reg	pipe_l0rxelec_set;
+	struct combphy_reg	u3_port_disable;
+	struct combphy_reg      u3_port_num;
+};
+
+struct rockchip_combphy_cfg {
+	const struct rockchip_combphy_grfcfg grfcfg;
+	int (*combphy_cfg)(struct rockchip_combphy_priv *priv);
+	int (*combphy_low_power_ctrl)(struct rockchip_combphy_priv *priv,
+				      bool en);
+};
+
+struct rockchip_combphy_priv {
+	bool phy_initialized;
+	bool phy_suspended;
+	u8 phy_type;
+	void __iomem *mmio;
+	struct device *dev;
+	struct clk *ref_clk;
+	struct phy *phy;
+	struct regmap *combphy_grf;
+	struct regmap *usb_pcie_grf;
+	struct reset_control *rsts[PHY_RESET_MAX];
+	const struct rockchip_combphy_cfg *cfg;
+};
+
+static const char *get_reset_name(enum rockchip_combphy_rst rst)
+{
+	switch (rst) {
+	case OTG_RSTN:
+		return "otg-rst";
+	case PHY_POR_RSTN:
+		return "combphy-por";
+	case PHY_APB_RSTN:
+		return "combphy-apb";
+	case PHY_PIPE_RSTN:
+		return "combphy-pipe";
+	case PHY_GRF_P_RSTN:
+		return "usb3phy_grf_p";
+	default:
+		return "invalid";
+	}
+}
+
+static inline bool param_read(struct regmap *base,
+			      const struct combphy_reg *reg, u32 val)
+{
+	int ret;
+	u32 mask, orig, tmp;
+
+	ret = regmap_read(base, reg->offset, &orig);
+	if (ret)
+		return false;
+
+	mask = GENMASK(reg->bitend, reg->bitstart);
+	tmp = (orig & mask) >> reg->bitstart;
+
+	return tmp == val;
+}
+
+static inline int param_write(struct regmap *base,
+			      const struct combphy_reg *reg, bool en)
+{
+	u32 val, mask, tmp;
+
+	tmp = en ? reg->enable : reg->disable;
+	mask = GENMASK(reg->bitend, reg->bitstart);
+	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+	return regmap_write(base, reg->offset, val);
+}
+
+static inline bool param_exped(void __iomem *base,
+			       const struct combphy_reg *reg,
+			       unsigned int value)
+{
+	int ret;
+	unsigned int tmp, orig;
+	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
+
+	ret = regmap_read(base, reg->offset, &orig);
+	if (ret)
+		return false;
+
+	tmp = (orig & mask) >> reg->bitstart;
+
+	return tmp == value;
+}
+
+static ssize_t u3phy_mode_show(struct device *device,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct rockchip_combphy_priv *priv = dev_get_drvdata(device);
+
+	if (param_exped(priv->usb_pcie_grf,
+			&priv->cfg->grfcfg.u3_port_num, 0))
+		return sprintf(buf, "u2\n");
+	else
+		return sprintf(buf, "u3\n");
+}
+
+static ssize_t u3phy_mode_store(struct device *device,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct rockchip_combphy_priv *priv = dev_get_drvdata(device);
+
+	if (!strncmp(buf, "u3", 2) &&
+	    param_exped(priv->usb_pcie_grf,
+			&priv->cfg->grfcfg.u3_port_num, 0)) {
+		/*
+		 * Enable USB 3.0 rx termination, need to select
+		 * pipe_l0_rxtermination from USB 3.0 controller.
+		 */
+		param_write(priv->combphy_grf,
+			    &priv->cfg->grfcfg.pipe_l0rxterm_sel, false);
+		/* Set xHCI USB 3.0 port number to 1 */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_num, true);
+		/* Enable xHCI USB 3.0 port */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_disable, false);
+		dev_info(priv->dev,
+			 "Set usb3.0 and usb2.0 mode successfully\n");
+	} else if (!strncmp(buf, "u2", 2) &&
+		   param_exped(priv->usb_pcie_grf,
+			       &priv->cfg->grfcfg.u3_port_num, 1)) {
+		/*
+		 * Disable USB 3.0 rx termination, need to select
+		 * pipe_l0_rxtermination from grf and remove rx
+		 * termimation by grf.
+		 */
+		param_write(priv->combphy_grf,
+			    &priv->cfg->grfcfg.pipe_l0rxterm_set, false);
+		param_write(priv->combphy_grf,
+			    &priv->cfg->grfcfg.pipe_l0rxterm_sel, true);
+		/* Set xHCI USB 3.0 port number to 0 */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_num, false);
+		/* Disable xHCI USB 3.0 port */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_disable, true);
+		/*
+		 * Note:
+		 * Don't disable the USB 3.0 PIPE pclk here(set reg
+		 * pipe_usb3_sel to false), because USB 3.0 PHY depend
+		 * on this clk, if we disable it, we need to reinit
+		 * the USB 3.0 PHY when use USB 3.0 mode, in order to
+		 * simplify the process, don't disable this PIPE pclk.
+		 */
+		dev_info(priv->dev, "Set usb2.0 only mode successfully\n");
+	} else {
+		dev_info(priv->dev, "Same or illegal mode\n");
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(u3phy_mode);
+
+static struct attribute *rockchip_combphy_u3mode_attrs[] = {
+	&dev_attr_u3phy_mode.attr,
+	NULL,
+};
+
+static struct attribute_group rockchip_combphy_u3mode_attr_group = {
+	.name = NULL,	/* we want them in the same directory */
+	.attrs = rockchip_combphy_u3mode_attrs,
+};
+
+static u32 rockchip_combphy_pll_lock(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 mask, val;
+
+	grfcfg = &priv->cfg->grfcfg;
+	mask = GENMASK(grfcfg->pipe_pll_lock.bitend,
+		       grfcfg->pipe_pll_lock.bitstart);
+
+	regmap_read(priv->combphy_grf, grfcfg->pipe_pll_lock.offset, &val);
+	val = (val & mask) >> grfcfg->pipe_pll_lock.bitstart;
+
+	return val;
+}
+
+static u32 rockchip_combphy_is_ready(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 mask, val;
+
+	grfcfg = &priv->cfg->grfcfg;
+	mask = GENMASK(grfcfg->pipe_status_l0.bitend,
+		       grfcfg->pipe_status_l0.bitstart);
+
+	regmap_read(priv->combphy_grf, grfcfg->pipe_status_l0.offset, &val);
+	val = (val & mask) >> grfcfg->pipe_status_l0.bitstart;
+
+	return val;
+}
+
+static int phy_pcie_init(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 val;
+	int ret = 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	/* reset PCIe phy to default configuration */
+	reset_control_assert(priv->rsts[PHY_POR_RSTN]);
+	reset_control_assert(priv->rsts[PHY_APB_RSTN]);
+	reset_control_assert(priv->rsts[PHY_PIPE_RSTN]);
+
+	reset_control_deassert(priv->rsts[PHY_POR_RSTN]);
+	/* Wait PHY power on stable */
+	udelay(5);
+	reset_control_deassert(priv->rsts[PHY_APB_RSTN]);
+	udelay(5);
+
+	/* Set rxtermination for lane0 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0rxterm_set, true);
+	/* Set rxtermination for lane1 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1rxterm_set, true);
+	/* Select pipe_l0_rxtermination from grf */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0rxterm_sel, true);
+	/* Select pipe_l1_rxtermination from grf */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1rxterm_sel, true);
+	/* Select rxelecidle_disable and txcommonmode from PCIe controller */
+	param_write(priv->combphy_grf, &grfcfg->pipe_txrx_sel, false);
+
+	/* Start to configurate PHY registers for PCIE. */
+	if (priv->cfg->combphy_cfg) {
+		ret = priv->cfg->combphy_cfg(priv);
+		if (ret)
+			goto error;
+	}
+
+	/* Wait Tx PLL lock */
+	usleep_range(300, 350);
+	ret = readx_poll_timeout_atomic(rockchip_combphy_pll_lock, priv, val,
+					val == grfcfg->pipe_pll_lock.enable,
+					10, 1000);
+	if (ret) {
+		dev_err(priv->dev, "wait phy PLL lock timeout\n");
+		goto error;
+	}
+
+	reset_control_deassert(priv->rsts[PHY_PIPE_RSTN]);
+error:
+	return ret;
+}
+
+static int phy_u3_init(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 val;
+	int ret = 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	/* Reset the USB3 controller first. */
+	reset_control_assert(priv->rsts[OTG_RSTN]);
+
+	reset_control_deassert(priv->rsts[PHY_POR_RSTN]);
+	/* Wait PHY power on stable. */
+	udelay(5);
+
+	reset_control_deassert(priv->rsts[PHY_APB_RSTN]);
+	udelay(5);
+
+	/*
+	 * Start to configurate PHY registers for USB3.
+	 * Note: set operation must be done before corresponding
+	 * sel operation, otherwise, the PIPE PHY status lane0
+	 * may be unable to get ready.
+	 */
+
+	/* Disable PHY lane1 which isn't needed for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1_sel, true);
+
+	/* Set PHY Tx and Rx for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_txrx_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_txrx_sel, true);
+
+	/* Set PHY PIPE MAC pclk request */
+	param_write(priv->combphy_grf, &grfcfg->pipe_clk_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_clk_sel, true);
+
+	/* Set PHY PIPE rate for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_rate_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_rate_sel, true);
+
+	/* Set PHY mode for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_mode_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_mode_sel, true);
+
+	/* Set PHY data bus width for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_width_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_width_sel, true);
+
+	/* Select PIPE for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_usb3_sel, true);
+
+	if (priv->cfg->combphy_cfg) {
+		ret = priv->cfg->combphy_cfg(priv);
+		if (ret)
+			goto error;
+	}
+
+	/* Wait Tx PLL lock */
+	usleep_range(300, 350);
+	ret = readx_poll_timeout_atomic(rockchip_combphy_pll_lock, priv, val,
+					val == grfcfg->pipe_pll_lock.enable,
+					10, 1000);
+	if (ret) {
+		dev_err(priv->dev, "wait phy PLL lock timeout\n");
+		goto error;
+	}
+
+	reset_control_deassert(priv->rsts[PHY_PIPE_RSTN]);
+
+	/* Wait PIPE PHY status lane0 ready */
+	ret = readx_poll_timeout_atomic(rockchip_combphy_is_ready, priv, val,
+					val == grfcfg->pipe_status_l0.enable,
+					10, 1000);
+	if (ret) {
+		dev_err(priv->dev, "wait phy status lane0 ready timeout\n");
+		goto error;
+	}
+
+	reset_control_deassert(priv->rsts[OTG_RSTN]);
+
+error:
+	return ret;
+}
+
+static int rockchip_combphy_set_phy_type(struct rockchip_combphy_priv *priv)
+{
+	int ret = 0;
+
+	if (priv->phy_initialized)
+		return ret;
+
+	switch (priv->phy_type) {
+	case PHY_TYPE_PCIE:
+		ret = phy_pcie_init(priv);
+		break;
+	case PHY_TYPE_USB3:
+		ret = phy_u3_init(priv);
+		if (ret)
+			return ret;
+
+		/* Attributes */
+		ret = sysfs_create_group(&priv->dev->kobj,
+					 &rockchip_combphy_u3mode_attr_group);
+		break;
+	default:
+		dev_err(priv->dev, "incompatible PHY type\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int rockchip_combphy_init(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	int ret;
+
+	ret = clk_prepare_enable(priv->ref_clk);
+	if (ret) {
+		dev_err(priv->dev, "failed to enable ref_clk\n");
+		return ret;
+	}
+
+	ret = rockchip_combphy_set_phy_type(priv);
+	if (ret) {
+		dev_err(priv->dev, "failed to set phy type\n");
+		return ret;
+	}
+
+	priv->phy_initialized = true;
+
+	return 0;
+}
+
+static int rockchip_combphy_exit(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+
+	/*
+	 * Note: don't assert PHY reset here, because
+	 * we set many phy configurations during phy
+	 * init to reduce PHY power consumption, if we
+	 * assert PHY reset here, these configurations
+	 * will be lost, and increase power consumption.
+	 */
+	clk_disable_unprepare(priv->ref_clk);
+
+	/* in case of waiting phy PLL lock timeout */
+	if (priv->phy_type == PHY_TYPE_PCIE) {
+		reset_control_assert(priv->rsts[PHY_GRF_P_RSTN]);
+		udelay(5);
+		reset_control_deassert(priv->rsts[PHY_GRF_P_RSTN]);
+		priv->phy_initialized = false;
+	}
+
+	return 0;
+}
+
+static int rockchip_combphy_power_on(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	const struct rockchip_combphy_grfcfg *grfcfg;
+
+	if (!priv->phy_suspended)
+		return 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	if (priv->phy_type == PHY_TYPE_USB3) {
+		if (priv->cfg->combphy_low_power_ctrl)
+			priv->cfg->combphy_low_power_ctrl(priv, false);
+
+		/* Enable lane 0 squelch detection  */
+		param_write(priv->combphy_grf, &grfcfg->pipe_l0rxelec_set,
+			    false);
+
+		/*
+		 * Check if lane 0 powerdown is already
+		 * controlled by USB 3.0 controller.
+		 */
+		if (param_read(priv->combphy_grf,
+			       &grfcfg->pipe_l0pd_sel, 0))
+			goto done;
+
+		/* Exit to P0 from P3 */
+		param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, false);
+		usleep_range(250, 300);
+
+		/*
+		 * Set lane 0 powerdown to be controlled
+		 * by USB 3.0 controller.
+		 */
+		param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_sel, false);
+	}
+
+done:
+	priv->phy_suspended = false;
+	return 0;
+}
+
+static int rockchip_combphy_power_off(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	const struct rockchip_combphy_grfcfg *grfcfg;
+
+	if (priv->phy_suspended)
+		return 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	if (priv->phy_type != PHY_TYPE_USB3 &&
+	    priv->phy_type != PHY_TYPE_PCIE)
+		goto done;
+
+	/*
+	 * Check if lane 0 powerdown is already
+	 * controlled by grf and in P3 state.
+	 */
+	if (param_read(priv->combphy_grf,
+		       &grfcfg->pipe_l0pd_sel, 1) &&
+	    param_read(priv->combphy_grf,
+		       &grfcfg->pipe_l0pd_p3, 3))
+		goto done;
+
+	/* Exit to P0 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, false);
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_sel, true);
+	udelay(1);
+
+	/* Enter to P3 from P0 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, true);
+	udelay(2);
+
+	/*
+	 * Disable lane 0 squelch detection.
+	 * Note: if squelch detection is disabled,
+	 * the PHY can't detect LFPS.
+	 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0rxelec_set,
+		    true);
+
+	if (priv->cfg->combphy_low_power_ctrl)
+		priv->cfg->combphy_low_power_ctrl(priv, true);
+
+done:
+	priv->phy_suspended = true;
+	return 0;
+}
+
+static int rockchip_combphy_set_mode_ext(struct phy *phy,
+					 enum phy_mode mode, int submode)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	u32 reg;
+
+	if (priv->phy_type != PHY_TYPE_PCIE || mode != PHY_MODE_PCIE)
+		return -EINVAL;
+
+	reg = readl(priv->mmio + 0x21a8);
+
+	/*
+	 * PCI-e EP/RC runtime special cfg.
+	 * submode 1 is for EP, and 0 is for RC.
+	 */
+	if (submode == 1)
+		reg |= (0x1 << 2);
+	else if (submode == 0)
+		reg &= ~(0x1 << 2);
+	else
+		return -EINVAL;
+
+	writel(reg, priv->mmio + 0x21a8);
+	return 0;
+}
+
+static const struct phy_ops rockchip_combphy_ops = {
+	.init		= rockchip_combphy_init,
+	.exit		= rockchip_combphy_exit,
+	.power_on	= rockchip_combphy_power_on,
+	.power_off	= rockchip_combphy_power_off,
+	.set_mode	= rockchip_combphy_set_mode_ext,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *rockchip_combphy_xlate(struct device *dev,
+					  struct of_phandle_args *args)
+{
+	struct rockchip_combphy_priv *priv = dev_get_drvdata(dev);
+
+	if (args->args_count < 1) {
+		dev_err(dev, "invalid number of arguments\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (priv->phy_type != PHY_NONE &&
+	    priv->phy_type != args->args[0]) {
+		dev_err(dev, "type select %d overwriting phy type %d\n",
+			args->args[0], priv->phy_type);
+		return ERR_PTR(-ENODEV);
+	}
+
+	priv->phy_type = args->args[0];
+
+	if (priv->phy_type < PHY_TYPE_SATA ||
+	    priv->phy_type > PHY_TYPE_USB3) {
+		dev_err(dev, "invalid phy type select argument\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return priv->phy;
+}
+
+static int rockchip_combphy_parse_dt(struct device *dev,
+				     struct rockchip_combphy_priv *priv)
+{
+	u32 i;
+
+	priv->combphy_grf =
+		syscon_regmap_lookup_by_phandle(dev->of_node,
+						"rockchip,combphygrf");
+	if (IS_ERR(priv->combphy_grf)) {
+		dev_err(dev, "failed to find combphy grf regmap\n");
+		return PTR_ERR(priv->combphy_grf);
+	}
+
+	priv->usb_pcie_grf =
+		syscon_regmap_lookup_by_phandle(dev->of_node,
+						"rockchip,usbpciegrf");
+	if (IS_ERR(priv->usb_pcie_grf)) {
+		dev_err(dev, "failed to find usb_pcie_grf regmap\n");
+		return PTR_ERR(priv->usb_pcie_grf);
+	}
+
+	priv->ref_clk = devm_clk_get(dev, "refclk");
+	if (IS_ERR(priv->ref_clk)) {
+		dev_err(dev, "failed to find ref clock\n");
+		return PTR_ERR(priv->ref_clk);
+	}
+
+	for (i = 0; i < PHY_RESET_MAX; i++) {
+		priv->rsts[i] =
+			devm_reset_control_get(dev, get_reset_name(i));
+		if (IS_ERR(priv->rsts[i])) {
+			dev_warn(dev, "no %s reset control specified\n",
+				 get_reset_name(i));
+			priv->rsts[i] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_combphy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct rockchip_combphy_priv *priv;
+	struct resource *res;
+	const struct rockchip_combphy_cfg *phy_cfg;
+	int ret;
+
+	phy_cfg = of_device_get_match_data(dev);
+	if (!phy_cfg) {
+		dev_err(dev, "No OF match data provided\n");
+		return -EINVAL;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->mmio)) {
+		ret = PTR_ERR(priv->mmio);
+		return ret;
+	}
+
+	ret = rockchip_combphy_parse_dt(dev, priv);
+	if (ret) {
+		dev_err(dev, "parse dt failed, ret(%d)\n", ret);
+		return ret;
+	}
+
+	reset_control_assert(priv->rsts[PHY_POR_RSTN]);
+	reset_control_assert(priv->rsts[PHY_APB_RSTN]);
+	reset_control_assert(priv->rsts[PHY_PIPE_RSTN]);
+
+	priv->phy_type = PHY_NONE;
+	priv->dev = dev;
+	priv->cfg = phy_cfg;
+	priv->phy = devm_phy_create(dev, NULL, &rockchip_combphy_ops);
+	if (IS_ERR(priv->phy)) {
+		dev_err(dev, "failed to create combphy\n");
+		return PTR_ERR(priv->phy);
+	}
+
+	dev_set_drvdata(dev, priv);
+	phy_set_drvdata(priv->phy, priv);
+
+	phy_provider =
+		devm_of_phy_provider_register(dev,
+					      rockchip_combphy_xlate);
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static int rockchip_combphy_remove(struct platform_device *pdev)
+{
+	struct rockchip_combphy_priv *priv = platform_get_drvdata(pdev);
+
+	if (priv->phy_type == PHY_TYPE_USB3 &&
+	    priv->phy_initialized)
+		sysfs_remove_group(&priv->dev->kobj,
+				   &rockchip_combphy_u3mode_attr_group);
+
+	return 0;
+}
+
+static int rk1808_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+	unsigned long rate;
+	u32 reg;
+	bool ssc_en = false;
+
+	rate = clk_get_rate(priv->ref_clk);
+
+	/* Configure PHY reference clock frequency */
+	switch (rate) {
+	case 24000000:
+		/*
+		 * The default PHY refclk frequency
+		 * configuration is 24MHz.
+		 */
+		break;
+	case 25000000:
+		writel(0x00, priv->mmio + 0x2118);
+		writel(0x64, priv->mmio + 0x211c);
+		writel(0x01, priv->mmio + 0x2020);
+		writel(0x64, priv->mmio + 0x2028);
+		writel(0x21, priv->mmio + 0x2030);
+
+		if (priv->phy_type == PHY_TYPE_PCIE) {
+			writel(0x1,  priv->mmio + 0x3020);
+			writel(0x64, priv->mmio + 0x3028);
+			writel(0x21, priv->mmio + 0x3030);
+		}
+
+		break;
+	case 50000000:
+		writel(0x00, priv->mmio + 0x2118);
+		writel(0x32, priv->mmio + 0x211c);
+		writel(0x01, priv->mmio + 0x2020);
+		writel(0x32, priv->mmio + 0x2028);
+		writel(0x21, priv->mmio + 0x2030);
+		break;
+	default:
+		dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
+		return -EINVAL;
+	}
+
+	if (priv->phy_type == PHY_TYPE_PCIE) {
+		/* turn on pcie phy pd */
+		writel(0x08400000, priv->mmio + 0x0);
+		writel(0x03030000, priv->mmio + 0x8);
+
+		/* Adjust Lane 0 Rx interface timing */
+		writel(0x20, priv->mmio + 0x20ac);
+		writel(0x12, priv->mmio + 0x20c8);
+		writel(0x76, priv->mmio + 0x2150);
+
+		/* Adjust Lane 1 Rx interface timing */
+		writel(0x20, priv->mmio + 0x30ac);
+		writel(0x12, priv->mmio + 0x30c8);
+		writel(0x76, priv->mmio + 0x3150);
+		/* Set PHY output refclk path */
+		writel(0x0, priv->mmio + 0x21a4);
+		writel(0x0, priv->mmio + 0x21a8);
+		writel(0xb, priv->mmio + 0x21ec);
+
+		/* Physical ordered set for PCIe */
+		writel(0x02, priv->mmio + 0x45c0);
+		writel(0x83, priv->mmio + 0x45c4);
+		writel(0x03, priv->mmio + 0x45c8);
+		writel(0x43, priv->mmio + 0x45cc);
+		writel(0x00, priv->mmio + 0x45d0);
+		writel(0xbc, priv->mmio + 0x45d4);
+
+		/* Boost pre-emphasis */
+		writel(0xaa, priv->mmio + 0x21b8);
+		writel(0xaa, priv->mmio + 0x31b8);
+	} else if (priv->phy_type == PHY_TYPE_USB3) {
+		/*
+		 * Disable PHY Lane 1 which isn't needed
+		 * for USB3 to reduce power consumption.
+		 */
+		/* Lane 1 cdr power down */
+		writel(0x09, priv->mmio + 0x3148);
+
+		/* Lane 1 rx bias disable */
+		writel(0x01, priv->mmio + 0x21cc);
+
+		/* Lane 1 cdr disable */
+		writel(0x08, priv->mmio + 0x30c4);
+		writel(0x08, priv->mmio + 0x20f4);
+
+		/* Lane 1 rx lock disable and tx bias disable */
+		writel(0x12, priv->mmio + 0x3150);
+
+		/* Lane 1 rx termination disable, and tx_cmenb disable */
+		writel(0x04, priv->mmio + 0x3080);
+
+		/* Lane 1 tx termination disable */
+		writel(0x1d, priv->mmio + 0x3090);
+
+		/* Lane 1 tx driver disable */
+		writel(0x50, priv->mmio + 0x21c4);
+		writel(0x10, priv->mmio + 0x2050);
+
+		/* Lane 1 txldo_refsel disable */
+		writel(0x81, priv->mmio + 0x31a8);
+
+		/* Lane 1 txdetrx_en disable */
+		writel(0x00, priv->mmio + 0x31e8);
+
+		/* Lane 1 rxcm_en disable */
+		writel(0x08, priv->mmio + 0x30c0);
+
+		/* Adjust Lane 0 Rx interface timing */
+		writel(0x20, priv->mmio + 0x20ac);
+
+		/* Set and enable SSC */
+		switch (rate) {
+		case 24000000:
+			/* Set SSC rate to 31.25KHz */
+			reg = readl(priv->mmio + 0x2108);
+			reg = (reg & ~0xf) | 0x1;
+			writel(reg, priv->mmio + 0x2108);
+			ssc_en = true;
+			break;
+		case 25000000:
+			/* Set SSC rate to 32.55KHz */
+			reg = readl(priv->mmio + 0x2108);
+			reg = (reg & ~0xf) | 0x6;
+			writel(reg, priv->mmio + 0x2108);
+			ssc_en = true;
+			break;
+		default:
+			dev_warn(priv->dev,
+				 "failed to set SSC on rate: %lu\n", rate);
+			break;
+		}
+
+		if (ssc_en) {
+			/* Enable SSC */
+			reg = readl(priv->mmio + 0x2120);
+			reg &= ~BIT(4);
+			writel(reg, priv->mmio + 0x2120);
+
+			reg = readl(priv->mmio + 0x2000);
+			reg &= ~0x6;
+			writel(reg, priv->mmio + 0x2000);
+		}
+
+		/*
+		 * Tuning Tx:
+		 * offset 0x21b8 bit[7:4]: lane 0 TX driver swing
+		 * tuning bits with weight, "1111" represents the
+		 * largest swing and "0000" the smallest.
+		 */
+		reg = readl(priv->mmio + 0x21b8);
+		reg = (reg & ~0xf0) | 0xe0;
+		writel(reg, priv->mmio + 0x21b8);
+
+		/*
+		 * Tuning Rx for RJTL:
+		 * Decrease CDR Chump Bump current.
+		 */
+		reg = readl(priv->mmio + 0x20c8);
+		reg = (reg & ~0x6) | BIT(1);
+		writel(reg, priv->mmio + 0x20c8);
+		reg = readl(priv->mmio + 0x2150);
+		reg |= BIT(2);
+		writel(reg, priv->mmio + 0x2150);
+	} else {
+		dev_err(priv->dev, "failed to cfg incompatible PHY type\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rk1808_combphy_low_power_control(struct rockchip_combphy_priv *priv,
+					    bool en)
+{
+	if (priv->phy_type != PHY_TYPE_USB3) {
+		/* turn off pcie phy pd */
+		writel(0x08400840, priv->mmio + 0x0);
+		writel(0x03030303, priv->mmio + 0x8);
+
+		/* enter PCIe phy low power mode */
+		writel(0x36, priv->mmio + 0x2150);
+		writel(0x36, priv->mmio + 0x3150);
+		writel(0x02, priv->mmio + 0x21e8);
+		writel(0x02, priv->mmio + 0x31e8);
+		writel(0x0c, priv->mmio + 0x2080);
+		writel(0x0c, priv->mmio + 0x3080);
+		writel(0x08, priv->mmio + 0x20c0);
+		writel(0x08, priv->mmio + 0x30c0);
+		writel(0x08, priv->mmio + 0x2058);
+
+		writel(0x10, priv->mmio + 0x2044);
+		writel(0x10, priv->mmio + 0x21a8);
+		writel(0x10, priv->mmio + 0x31a8);
+		writel(0x08, priv->mmio + 0x2058);
+		writel(0x08, priv->mmio + 0x3058);
+		writel(0x40, priv->mmio + 0x205c);
+		writel(0x40, priv->mmio + 0x305c);
+		writel(0x08, priv->mmio + 0x2184);
+		writel(0x08, priv->mmio + 0x3184);
+		writel(0x00, priv->mmio + 0x2150);
+		writel(0x00, priv->mmio + 0x3150);
+		writel(0x10, priv->mmio + 0x20e0);
+		writel(0x00, priv->mmio + 0x21e8);
+		writel(0x00, priv->mmio + 0x31e8);
+
+		return 0;
+	}
+
+	if (en) {
+		/* Lane 0 tx_biasen disable */
+		writel(0x36, priv->mmio + 0x2150);
+
+		/* Lane 0 txdetrx_en disable */
+		writel(0x02, priv->mmio + 0x21e8);
+
+		/* Lane 0 tx_cmenb disable */
+		writel(0x0c, priv->mmio + 0x2080);
+
+		/* Lane 0 rxcm_en disable */
+		writel(0x08, priv->mmio + 0x20c0);
+
+		/* Lane 0 and Lane 1 bg_pwrdn */
+		writel(0x10, priv->mmio + 0x2044);
+
+		/* Lane 0 and Lane 1 rcomp_osenseampen disable */
+		writel(0x08, priv->mmio + 0x2058);
+
+		/* Lane 0 txldo_refsel disable and LDO disable */
+		writel(0x91, priv->mmio + 0x21a8);
+
+		/* Lane 1 LDO disable */
+		writel(0x91, priv->mmio + 0x31a8);
+	} else {
+		/* Lane 0 tx_biasen enable */
+		writel(0x76, priv->mmio + 0x2150);
+
+		/* Lane 0 txdetrx_en enable */
+		writel(0x02, priv->mmio + 0x21e8);
+
+		/* Lane 0 tx_cmenb enable */
+		writel(0x08, priv->mmio + 0x2080);
+
+		/* Lane 0 rxcm_en enable */
+		writel(0x18, priv->mmio + 0x20c0);
+
+		/* Lane 0 and Lane 1 bg_pwrdn */
+		writel(0x00, priv->mmio + 0x2044);
+
+		/* Lane 0 and Lane 1 rcomp_osenseampen enable */
+		writel(0x28, priv->mmio + 0x2058);
+
+		/* Lane 0 txldo_refsel enable and LDO enable */
+		writel(0x01, priv->mmio + 0x21a8);
+
+		/* Lane 1 LDO enable */
+		writel(0x81, priv->mmio + 0x31a8);
+	}
+
+	return 0;
+}
+
+static const struct rockchip_combphy_cfg rk1808_combphy_cfgs = {
+	.grfcfg	= {
+		.pipe_l1_sel	= { 0x0000, 15, 11, 0x00, 0x1f },
+		.pipe_l1_set	= { 0x0008, 13, 8, 0x00, 0x13 },
+		.pipe_l1rxterm_sel = { 0x0000, 12, 12, 0x0, 0x1 },
+		.pipe_l1pd_sel	= { 0x0000, 11, 11, 0x0, 0x1},
+		.pipe_l1pd_p3	= { 0x0008, 9, 8, 0x0, 0x3 },
+		.pipe_l0rxterm_sel = { 0x0000, 7, 7, 0x0, 0x1 },
+		.pipe_l0pd_sel	= { 0x0000, 6, 6, 0x0, 0x1 },
+		.pipe_l0pd_p3	= { 0x0008, 1, 0, 0x0, 0x3 },
+		.pipe_clk_sel	= { 0x0000, 3, 3, 0x0, 0x1 },
+		.pipe_clk_set	= { 0x0004, 7, 6, 0x1, 0x0 },
+		.pipe_rate_sel	= { 0x0000, 2, 2, 0x0, 0x1 },
+		.pipe_rate_set	= { 0x0004, 5, 4, 0x0, 0x1 },
+		.pipe_mode_sel	= { 0x0000, 1, 1, 0x0, 0x1 },
+		.pipe_mode_set	= { 0x0004, 3, 2, 0x0, 0x1 },
+		.pipe_txrx_sel	= { 0x0004, 15, 8, 0x10, 0x2f },
+		.pipe_txrx_set	= { 0x0008, 15, 14, 0x0, 0x3 },
+		.pipe_l1rxterm_set = { 0x0008, 10, 10, 0x0, 0x1 },
+		.pipe_l0rxterm_set = { 0x0008, 2, 2, 0x0, 0x1 },
+		.pipe_l0rxelec_set = { 0x0008, 6, 6, 0x0, 0x1 },
+		.pipe_width_sel	= { 0x0000, 0, 0, 0x0, 0x1 },
+		.pipe_width_set	= { 0x0004, 1, 0, 0x2, 0x0 },
+		.pipe_usb3_sel	= { 0x000c, 0, 0, 0x0, 0x1 },
+		.pipe_pll_lock	= { 0x0034, 14, 14, 0x0, 0x1 },
+		.pipe_status_l0	= { 0x0034, 7, 7, 0x1, 0x0 },
+		.u3_port_disable = { 0x0434, 0, 0, 0, 1},
+		.u3_port_num	= { 0x0434, 15, 12, 0, 1},
+	},
+	.combphy_cfg		= rk1808_combphy_cfg,
+	.combphy_low_power_ctrl	= rk1808_combphy_low_power_control,
+};
+
+static const struct of_device_id rockchip_combphy_of_match[] = {
+	{
+		.compatible = "rockchip,rk1808-combphy",
+		.data = &rk1808_combphy_cfgs,
+	},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_combphy_of_match);
+
+static struct platform_driver rockchip_combphy_driver = {
+	.probe	= rockchip_combphy_probe,
+	.remove = rockchip_combphy_remove,
+	.driver = {
+		.name = "rockchip-combphy",
+		.of_match_table = rockchip_combphy_of_match,
+	},
+};
+module_platform_driver(rockchip_combphy_driver);
+
+MODULE_AUTHOR("Rockchip Inc.");
+MODULE_DESCRIPTION("Rockchip USB3.0 and PCIE COMBPHY driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1




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

* [PATCH 2/6] phy/rockchip: inno-combophy: Add initial support
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	Shawn Lin, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu

From: William Wu <william.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

Add initial support for inno-combophy driver which supports
USB3.0 host/device/otg mode as well as PCIe EP/RC mode.

Signed-off-by: William Wu <william.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---

 drivers/phy/rockchip/Kconfig                     |    8 +
 drivers/phy/rockchip/Makefile                    |    1 +
 drivers/phy/rockchip/phy-rockchip-inno-combphy.c | 1056 ++++++++++++++++++++++
 3 files changed, 1065 insertions(+)
 create mode 100644 drivers/phy/rockchip/phy-rockchip-inno-combphy.c

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 0824b9d..267306a 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -16,6 +16,14 @@ config PHY_ROCKCHIP_EMMC
 	help
 	  Enable this to support the Rockchip EMMC PHY.
 
+config PHY_ROCKCHIP_INNO_COMBPHY
+	tristate "Rockchip INNO USB 3.0 and PCIe COMBPHY Driver"
+	depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST
+	select GENERIC_PHY
+	help
+	  Enable this to support the Rockchip SoCs COMBPHY.
+	  If unsure, say N.
+
 config PHY_ROCKCHIP_INNO_HDMI
 	tristate "Rockchip INNO HDMI PHY Driver"
 	depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile
index 9f59a81..6813b95 100644
--- a/drivers/phy/rockchip/Makefile
+++ b/drivers/phy/rockchip/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC)		+= phy-rockchip-emmc.o
+obj-$(CONFIG_PHY_ROCKCHIP_INNO_COMBPHY)	+= phy-rockchip-inno-combphy.o
 obj-$(CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY)	+= phy-rockchip-inno-dsidphy.o
 obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI)	+= phy-rockchip-inno-hdmi.o
 obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2)	+= phy-rockchip-inno-usb2.o
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-combphy.c b/drivers/phy/rockchip/phy-rockchip-inno-combphy.c
new file mode 100644
index 0000000..4656ecc
--- /dev/null
+++ b/drivers/phy/rockchip/phy-rockchip-inno-combphy.c
@@ -0,0 +1,1056 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip USB3.0 and PCIE COMBPHY with Innosilicon IP block driver
+ *
+ * Copyright (C) 2018 Fuzhou Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <dt-bindings/phy/phy.h>
+
+#define BIT_WRITEABLE_SHIFT	16
+
+struct rockchip_combphy_priv;
+
+enum rockchip_combphy_rst {
+	OTG_RSTN	= 0,
+	PHY_POR_RSTN	= 1,
+	PHY_APB_RSTN	= 2,
+	PHY_PIPE_RSTN	= 3,
+	PHY_GRF_P_RSTN  = 4,
+	PHY_RESET_MAX	= 5,
+};
+
+struct combphy_reg {
+	u32	offset;
+	u32	bitend;
+	u32	bitstart;
+	u32	disable;
+	u32	enable;
+};
+
+struct rockchip_combphy_grfcfg {
+	struct combphy_reg	pipe_l1_sel;
+	struct combphy_reg	pipe_l1_set;
+	struct combphy_reg	pipe_l1pd_sel;
+	struct combphy_reg	pipe_l1pd_p3;
+	struct combphy_reg	pipe_l0pd_sel;
+	struct combphy_reg	pipe_l0pd_p3;
+	struct combphy_reg	pipe_clk_sel;
+	struct combphy_reg	pipe_clk_set;
+	struct combphy_reg	pipe_rate_sel;
+	struct combphy_reg	pipe_rate_set;
+	struct combphy_reg	pipe_mode_sel;
+	struct combphy_reg	pipe_mode_set;
+	struct combphy_reg	pipe_txrx_sel;
+	struct combphy_reg	pipe_txrx_set;
+	struct combphy_reg	pipe_width_sel;
+	struct combphy_reg	pipe_width_set;
+	struct combphy_reg	pipe_usb3_sel;
+	struct combphy_reg	pipe_pll_lock;
+	struct combphy_reg	pipe_status_l0;
+	struct combphy_reg	pipe_l0rxterm_sel;
+	struct combphy_reg	pipe_l1rxterm_sel;
+	struct combphy_reg	pipe_l0rxterm_set;
+	struct combphy_reg	pipe_l1rxterm_set;
+	struct combphy_reg	pipe_l0rxelec_set;
+	struct combphy_reg	u3_port_disable;
+	struct combphy_reg      u3_port_num;
+};
+
+struct rockchip_combphy_cfg {
+	const struct rockchip_combphy_grfcfg grfcfg;
+	int (*combphy_cfg)(struct rockchip_combphy_priv *priv);
+	int (*combphy_low_power_ctrl)(struct rockchip_combphy_priv *priv,
+				      bool en);
+};
+
+struct rockchip_combphy_priv {
+	bool phy_initialized;
+	bool phy_suspended;
+	u8 phy_type;
+	void __iomem *mmio;
+	struct device *dev;
+	struct clk *ref_clk;
+	struct phy *phy;
+	struct regmap *combphy_grf;
+	struct regmap *usb_pcie_grf;
+	struct reset_control *rsts[PHY_RESET_MAX];
+	const struct rockchip_combphy_cfg *cfg;
+};
+
+static const char *get_reset_name(enum rockchip_combphy_rst rst)
+{
+	switch (rst) {
+	case OTG_RSTN:
+		return "otg-rst";
+	case PHY_POR_RSTN:
+		return "combphy-por";
+	case PHY_APB_RSTN:
+		return "combphy-apb";
+	case PHY_PIPE_RSTN:
+		return "combphy-pipe";
+	case PHY_GRF_P_RSTN:
+		return "usb3phy_grf_p";
+	default:
+		return "invalid";
+	}
+}
+
+static inline bool param_read(struct regmap *base,
+			      const struct combphy_reg *reg, u32 val)
+{
+	int ret;
+	u32 mask, orig, tmp;
+
+	ret = regmap_read(base, reg->offset, &orig);
+	if (ret)
+		return false;
+
+	mask = GENMASK(reg->bitend, reg->bitstart);
+	tmp = (orig & mask) >> reg->bitstart;
+
+	return tmp == val;
+}
+
+static inline int param_write(struct regmap *base,
+			      const struct combphy_reg *reg, bool en)
+{
+	u32 val, mask, tmp;
+
+	tmp = en ? reg->enable : reg->disable;
+	mask = GENMASK(reg->bitend, reg->bitstart);
+	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+	return regmap_write(base, reg->offset, val);
+}
+
+static inline bool param_exped(void __iomem *base,
+			       const struct combphy_reg *reg,
+			       unsigned int value)
+{
+	int ret;
+	unsigned int tmp, orig;
+	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
+
+	ret = regmap_read(base, reg->offset, &orig);
+	if (ret)
+		return false;
+
+	tmp = (orig & mask) >> reg->bitstart;
+
+	return tmp == value;
+}
+
+static ssize_t u3phy_mode_show(struct device *device,
+			       struct device_attribute *attr,
+			       char *buf)
+{
+	struct rockchip_combphy_priv *priv = dev_get_drvdata(device);
+
+	if (param_exped(priv->usb_pcie_grf,
+			&priv->cfg->grfcfg.u3_port_num, 0))
+		return sprintf(buf, "u2\n");
+	else
+		return sprintf(buf, "u3\n");
+}
+
+static ssize_t u3phy_mode_store(struct device *device,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct rockchip_combphy_priv *priv = dev_get_drvdata(device);
+
+	if (!strncmp(buf, "u3", 2) &&
+	    param_exped(priv->usb_pcie_grf,
+			&priv->cfg->grfcfg.u3_port_num, 0)) {
+		/*
+		 * Enable USB 3.0 rx termination, need to select
+		 * pipe_l0_rxtermination from USB 3.0 controller.
+		 */
+		param_write(priv->combphy_grf,
+			    &priv->cfg->grfcfg.pipe_l0rxterm_sel, false);
+		/* Set xHCI USB 3.0 port number to 1 */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_num, true);
+		/* Enable xHCI USB 3.0 port */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_disable, false);
+		dev_info(priv->dev,
+			 "Set usb3.0 and usb2.0 mode successfully\n");
+	} else if (!strncmp(buf, "u2", 2) &&
+		   param_exped(priv->usb_pcie_grf,
+			       &priv->cfg->grfcfg.u3_port_num, 1)) {
+		/*
+		 * Disable USB 3.0 rx termination, need to select
+		 * pipe_l0_rxtermination from grf and remove rx
+		 * termimation by grf.
+		 */
+		param_write(priv->combphy_grf,
+			    &priv->cfg->grfcfg.pipe_l0rxterm_set, false);
+		param_write(priv->combphy_grf,
+			    &priv->cfg->grfcfg.pipe_l0rxterm_sel, true);
+		/* Set xHCI USB 3.0 port number to 0 */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_num, false);
+		/* Disable xHCI USB 3.0 port */
+		param_write(priv->usb_pcie_grf,
+			    &priv->cfg->grfcfg.u3_port_disable, true);
+		/*
+		 * Note:
+		 * Don't disable the USB 3.0 PIPE pclk here(set reg
+		 * pipe_usb3_sel to false), because USB 3.0 PHY depend
+		 * on this clk, if we disable it, we need to reinit
+		 * the USB 3.0 PHY when use USB 3.0 mode, in order to
+		 * simplify the process, don't disable this PIPE pclk.
+		 */
+		dev_info(priv->dev, "Set usb2.0 only mode successfully\n");
+	} else {
+		dev_info(priv->dev, "Same or illegal mode\n");
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(u3phy_mode);
+
+static struct attribute *rockchip_combphy_u3mode_attrs[] = {
+	&dev_attr_u3phy_mode.attr,
+	NULL,
+};
+
+static struct attribute_group rockchip_combphy_u3mode_attr_group = {
+	.name = NULL,	/* we want them in the same directory */
+	.attrs = rockchip_combphy_u3mode_attrs,
+};
+
+static u32 rockchip_combphy_pll_lock(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 mask, val;
+
+	grfcfg = &priv->cfg->grfcfg;
+	mask = GENMASK(grfcfg->pipe_pll_lock.bitend,
+		       grfcfg->pipe_pll_lock.bitstart);
+
+	regmap_read(priv->combphy_grf, grfcfg->pipe_pll_lock.offset, &val);
+	val = (val & mask) >> grfcfg->pipe_pll_lock.bitstart;
+
+	return val;
+}
+
+static u32 rockchip_combphy_is_ready(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 mask, val;
+
+	grfcfg = &priv->cfg->grfcfg;
+	mask = GENMASK(grfcfg->pipe_status_l0.bitend,
+		       grfcfg->pipe_status_l0.bitstart);
+
+	regmap_read(priv->combphy_grf, grfcfg->pipe_status_l0.offset, &val);
+	val = (val & mask) >> grfcfg->pipe_status_l0.bitstart;
+
+	return val;
+}
+
+static int phy_pcie_init(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 val;
+	int ret = 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	/* reset PCIe phy to default configuration */
+	reset_control_assert(priv->rsts[PHY_POR_RSTN]);
+	reset_control_assert(priv->rsts[PHY_APB_RSTN]);
+	reset_control_assert(priv->rsts[PHY_PIPE_RSTN]);
+
+	reset_control_deassert(priv->rsts[PHY_POR_RSTN]);
+	/* Wait PHY power on stable */
+	udelay(5);
+	reset_control_deassert(priv->rsts[PHY_APB_RSTN]);
+	udelay(5);
+
+	/* Set rxtermination for lane0 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0rxterm_set, true);
+	/* Set rxtermination for lane1 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1rxterm_set, true);
+	/* Select pipe_l0_rxtermination from grf */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0rxterm_sel, true);
+	/* Select pipe_l1_rxtermination from grf */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1rxterm_sel, true);
+	/* Select rxelecidle_disable and txcommonmode from PCIe controller */
+	param_write(priv->combphy_grf, &grfcfg->pipe_txrx_sel, false);
+
+	/* Start to configurate PHY registers for PCIE. */
+	if (priv->cfg->combphy_cfg) {
+		ret = priv->cfg->combphy_cfg(priv);
+		if (ret)
+			goto error;
+	}
+
+	/* Wait Tx PLL lock */
+	usleep_range(300, 350);
+	ret = readx_poll_timeout_atomic(rockchip_combphy_pll_lock, priv, val,
+					val == grfcfg->pipe_pll_lock.enable,
+					10, 1000);
+	if (ret) {
+		dev_err(priv->dev, "wait phy PLL lock timeout\n");
+		goto error;
+	}
+
+	reset_control_deassert(priv->rsts[PHY_PIPE_RSTN]);
+error:
+	return ret;
+}
+
+static int phy_u3_init(struct rockchip_combphy_priv *priv)
+{
+	const struct rockchip_combphy_grfcfg *grfcfg;
+	u32 val;
+	int ret = 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	/* Reset the USB3 controller first. */
+	reset_control_assert(priv->rsts[OTG_RSTN]);
+
+	reset_control_deassert(priv->rsts[PHY_POR_RSTN]);
+	/* Wait PHY power on stable. */
+	udelay(5);
+
+	reset_control_deassert(priv->rsts[PHY_APB_RSTN]);
+	udelay(5);
+
+	/*
+	 * Start to configurate PHY registers for USB3.
+	 * Note: set operation must be done before corresponding
+	 * sel operation, otherwise, the PIPE PHY status lane0
+	 * may be unable to get ready.
+	 */
+
+	/* Disable PHY lane1 which isn't needed for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_l1_sel, true);
+
+	/* Set PHY Tx and Rx for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_txrx_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_txrx_sel, true);
+
+	/* Set PHY PIPE MAC pclk request */
+	param_write(priv->combphy_grf, &grfcfg->pipe_clk_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_clk_sel, true);
+
+	/* Set PHY PIPE rate for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_rate_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_rate_sel, true);
+
+	/* Set PHY mode for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_mode_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_mode_sel, true);
+
+	/* Set PHY data bus width for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_width_set, true);
+	param_write(priv->combphy_grf, &grfcfg->pipe_width_sel, true);
+
+	/* Select PIPE for USB3 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_usb3_sel, true);
+
+	if (priv->cfg->combphy_cfg) {
+		ret = priv->cfg->combphy_cfg(priv);
+		if (ret)
+			goto error;
+	}
+
+	/* Wait Tx PLL lock */
+	usleep_range(300, 350);
+	ret = readx_poll_timeout_atomic(rockchip_combphy_pll_lock, priv, val,
+					val == grfcfg->pipe_pll_lock.enable,
+					10, 1000);
+	if (ret) {
+		dev_err(priv->dev, "wait phy PLL lock timeout\n");
+		goto error;
+	}
+
+	reset_control_deassert(priv->rsts[PHY_PIPE_RSTN]);
+
+	/* Wait PIPE PHY status lane0 ready */
+	ret = readx_poll_timeout_atomic(rockchip_combphy_is_ready, priv, val,
+					val == grfcfg->pipe_status_l0.enable,
+					10, 1000);
+	if (ret) {
+		dev_err(priv->dev, "wait phy status lane0 ready timeout\n");
+		goto error;
+	}
+
+	reset_control_deassert(priv->rsts[OTG_RSTN]);
+
+error:
+	return ret;
+}
+
+static int rockchip_combphy_set_phy_type(struct rockchip_combphy_priv *priv)
+{
+	int ret = 0;
+
+	if (priv->phy_initialized)
+		return ret;
+
+	switch (priv->phy_type) {
+	case PHY_TYPE_PCIE:
+		ret = phy_pcie_init(priv);
+		break;
+	case PHY_TYPE_USB3:
+		ret = phy_u3_init(priv);
+		if (ret)
+			return ret;
+
+		/* Attributes */
+		ret = sysfs_create_group(&priv->dev->kobj,
+					 &rockchip_combphy_u3mode_attr_group);
+		break;
+	default:
+		dev_err(priv->dev, "incompatible PHY type\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int rockchip_combphy_init(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	int ret;
+
+	ret = clk_prepare_enable(priv->ref_clk);
+	if (ret) {
+		dev_err(priv->dev, "failed to enable ref_clk\n");
+		return ret;
+	}
+
+	ret = rockchip_combphy_set_phy_type(priv);
+	if (ret) {
+		dev_err(priv->dev, "failed to set phy type\n");
+		return ret;
+	}
+
+	priv->phy_initialized = true;
+
+	return 0;
+}
+
+static int rockchip_combphy_exit(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+
+	/*
+	 * Note: don't assert PHY reset here, because
+	 * we set many phy configurations during phy
+	 * init to reduce PHY power consumption, if we
+	 * assert PHY reset here, these configurations
+	 * will be lost, and increase power consumption.
+	 */
+	clk_disable_unprepare(priv->ref_clk);
+
+	/* in case of waiting phy PLL lock timeout */
+	if (priv->phy_type == PHY_TYPE_PCIE) {
+		reset_control_assert(priv->rsts[PHY_GRF_P_RSTN]);
+		udelay(5);
+		reset_control_deassert(priv->rsts[PHY_GRF_P_RSTN]);
+		priv->phy_initialized = false;
+	}
+
+	return 0;
+}
+
+static int rockchip_combphy_power_on(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	const struct rockchip_combphy_grfcfg *grfcfg;
+
+	if (!priv->phy_suspended)
+		return 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	if (priv->phy_type == PHY_TYPE_USB3) {
+		if (priv->cfg->combphy_low_power_ctrl)
+			priv->cfg->combphy_low_power_ctrl(priv, false);
+
+		/* Enable lane 0 squelch detection  */
+		param_write(priv->combphy_grf, &grfcfg->pipe_l0rxelec_set,
+			    false);
+
+		/*
+		 * Check if lane 0 powerdown is already
+		 * controlled by USB 3.0 controller.
+		 */
+		if (param_read(priv->combphy_grf,
+			       &grfcfg->pipe_l0pd_sel, 0))
+			goto done;
+
+		/* Exit to P0 from P3 */
+		param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, false);
+		usleep_range(250, 300);
+
+		/*
+		 * Set lane 0 powerdown to be controlled
+		 * by USB 3.0 controller.
+		 */
+		param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_sel, false);
+	}
+
+done:
+	priv->phy_suspended = false;
+	return 0;
+}
+
+static int rockchip_combphy_power_off(struct phy *phy)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	const struct rockchip_combphy_grfcfg *grfcfg;
+
+	if (priv->phy_suspended)
+		return 0;
+
+	grfcfg = &priv->cfg->grfcfg;
+
+	if (priv->phy_type != PHY_TYPE_USB3 &&
+	    priv->phy_type != PHY_TYPE_PCIE)
+		goto done;
+
+	/*
+	 * Check if lane 0 powerdown is already
+	 * controlled by grf and in P3 state.
+	 */
+	if (param_read(priv->combphy_grf,
+		       &grfcfg->pipe_l0pd_sel, 1) &&
+	    param_read(priv->combphy_grf,
+		       &grfcfg->pipe_l0pd_p3, 3))
+		goto done;
+
+	/* Exit to P0 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, false);
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_sel, true);
+	udelay(1);
+
+	/* Enter to P3 from P0 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0pd_p3, true);
+	udelay(2);
+
+	/*
+	 * Disable lane 0 squelch detection.
+	 * Note: if squelch detection is disabled,
+	 * the PHY can't detect LFPS.
+	 */
+	param_write(priv->combphy_grf, &grfcfg->pipe_l0rxelec_set,
+		    true);
+
+	if (priv->cfg->combphy_low_power_ctrl)
+		priv->cfg->combphy_low_power_ctrl(priv, true);
+
+done:
+	priv->phy_suspended = true;
+	return 0;
+}
+
+static int rockchip_combphy_set_mode_ext(struct phy *phy,
+					 enum phy_mode mode, int submode)
+{
+	struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
+	u32 reg;
+
+	if (priv->phy_type != PHY_TYPE_PCIE || mode != PHY_MODE_PCIE)
+		return -EINVAL;
+
+	reg = readl(priv->mmio + 0x21a8);
+
+	/*
+	 * PCI-e EP/RC runtime special cfg.
+	 * submode 1 is for EP, and 0 is for RC.
+	 */
+	if (submode == 1)
+		reg |= (0x1 << 2);
+	else if (submode == 0)
+		reg &= ~(0x1 << 2);
+	else
+		return -EINVAL;
+
+	writel(reg, priv->mmio + 0x21a8);
+	return 0;
+}
+
+static const struct phy_ops rockchip_combphy_ops = {
+	.init		= rockchip_combphy_init,
+	.exit		= rockchip_combphy_exit,
+	.power_on	= rockchip_combphy_power_on,
+	.power_off	= rockchip_combphy_power_off,
+	.set_mode	= rockchip_combphy_set_mode_ext,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *rockchip_combphy_xlate(struct device *dev,
+					  struct of_phandle_args *args)
+{
+	struct rockchip_combphy_priv *priv = dev_get_drvdata(dev);
+
+	if (args->args_count < 1) {
+		dev_err(dev, "invalid number of arguments\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (priv->phy_type != PHY_NONE &&
+	    priv->phy_type != args->args[0]) {
+		dev_err(dev, "type select %d overwriting phy type %d\n",
+			args->args[0], priv->phy_type);
+		return ERR_PTR(-ENODEV);
+	}
+
+	priv->phy_type = args->args[0];
+
+	if (priv->phy_type < PHY_TYPE_SATA ||
+	    priv->phy_type > PHY_TYPE_USB3) {
+		dev_err(dev, "invalid phy type select argument\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return priv->phy;
+}
+
+static int rockchip_combphy_parse_dt(struct device *dev,
+				     struct rockchip_combphy_priv *priv)
+{
+	u32 i;
+
+	priv->combphy_grf =
+		syscon_regmap_lookup_by_phandle(dev->of_node,
+						"rockchip,combphygrf");
+	if (IS_ERR(priv->combphy_grf)) {
+		dev_err(dev, "failed to find combphy grf regmap\n");
+		return PTR_ERR(priv->combphy_grf);
+	}
+
+	priv->usb_pcie_grf =
+		syscon_regmap_lookup_by_phandle(dev->of_node,
+						"rockchip,usbpciegrf");
+	if (IS_ERR(priv->usb_pcie_grf)) {
+		dev_err(dev, "failed to find usb_pcie_grf regmap\n");
+		return PTR_ERR(priv->usb_pcie_grf);
+	}
+
+	priv->ref_clk = devm_clk_get(dev, "refclk");
+	if (IS_ERR(priv->ref_clk)) {
+		dev_err(dev, "failed to find ref clock\n");
+		return PTR_ERR(priv->ref_clk);
+	}
+
+	for (i = 0; i < PHY_RESET_MAX; i++) {
+		priv->rsts[i] =
+			devm_reset_control_get(dev, get_reset_name(i));
+		if (IS_ERR(priv->rsts[i])) {
+			dev_warn(dev, "no %s reset control specified\n",
+				 get_reset_name(i));
+			priv->rsts[i] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_combphy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct rockchip_combphy_priv *priv;
+	struct resource *res;
+	const struct rockchip_combphy_cfg *phy_cfg;
+	int ret;
+
+	phy_cfg = of_device_get_match_data(dev);
+	if (!phy_cfg) {
+		dev_err(dev, "No OF match data provided\n");
+		return -EINVAL;
+	}
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(priv->mmio)) {
+		ret = PTR_ERR(priv->mmio);
+		return ret;
+	}
+
+	ret = rockchip_combphy_parse_dt(dev, priv);
+	if (ret) {
+		dev_err(dev, "parse dt failed, ret(%d)\n", ret);
+		return ret;
+	}
+
+	reset_control_assert(priv->rsts[PHY_POR_RSTN]);
+	reset_control_assert(priv->rsts[PHY_APB_RSTN]);
+	reset_control_assert(priv->rsts[PHY_PIPE_RSTN]);
+
+	priv->phy_type = PHY_NONE;
+	priv->dev = dev;
+	priv->cfg = phy_cfg;
+	priv->phy = devm_phy_create(dev, NULL, &rockchip_combphy_ops);
+	if (IS_ERR(priv->phy)) {
+		dev_err(dev, "failed to create combphy\n");
+		return PTR_ERR(priv->phy);
+	}
+
+	dev_set_drvdata(dev, priv);
+	phy_set_drvdata(priv->phy, priv);
+
+	phy_provider =
+		devm_of_phy_provider_register(dev,
+					      rockchip_combphy_xlate);
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static int rockchip_combphy_remove(struct platform_device *pdev)
+{
+	struct rockchip_combphy_priv *priv = platform_get_drvdata(pdev);
+
+	if (priv->phy_type == PHY_TYPE_USB3 &&
+	    priv->phy_initialized)
+		sysfs_remove_group(&priv->dev->kobj,
+				   &rockchip_combphy_u3mode_attr_group);
+
+	return 0;
+}
+
+static int rk1808_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+	unsigned long rate;
+	u32 reg;
+	bool ssc_en = false;
+
+	rate = clk_get_rate(priv->ref_clk);
+
+	/* Configure PHY reference clock frequency */
+	switch (rate) {
+	case 24000000:
+		/*
+		 * The default PHY refclk frequency
+		 * configuration is 24MHz.
+		 */
+		break;
+	case 25000000:
+		writel(0x00, priv->mmio + 0x2118);
+		writel(0x64, priv->mmio + 0x211c);
+		writel(0x01, priv->mmio + 0x2020);
+		writel(0x64, priv->mmio + 0x2028);
+		writel(0x21, priv->mmio + 0x2030);
+
+		if (priv->phy_type == PHY_TYPE_PCIE) {
+			writel(0x1,  priv->mmio + 0x3020);
+			writel(0x64, priv->mmio + 0x3028);
+			writel(0x21, priv->mmio + 0x3030);
+		}
+
+		break;
+	case 50000000:
+		writel(0x00, priv->mmio + 0x2118);
+		writel(0x32, priv->mmio + 0x211c);
+		writel(0x01, priv->mmio + 0x2020);
+		writel(0x32, priv->mmio + 0x2028);
+		writel(0x21, priv->mmio + 0x2030);
+		break;
+	default:
+		dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
+		return -EINVAL;
+	}
+
+	if (priv->phy_type == PHY_TYPE_PCIE) {
+		/* turn on pcie phy pd */
+		writel(0x08400000, priv->mmio + 0x0);
+		writel(0x03030000, priv->mmio + 0x8);
+
+		/* Adjust Lane 0 Rx interface timing */
+		writel(0x20, priv->mmio + 0x20ac);
+		writel(0x12, priv->mmio + 0x20c8);
+		writel(0x76, priv->mmio + 0x2150);
+
+		/* Adjust Lane 1 Rx interface timing */
+		writel(0x20, priv->mmio + 0x30ac);
+		writel(0x12, priv->mmio + 0x30c8);
+		writel(0x76, priv->mmio + 0x3150);
+		/* Set PHY output refclk path */
+		writel(0x0, priv->mmio + 0x21a4);
+		writel(0x0, priv->mmio + 0x21a8);
+		writel(0xb, priv->mmio + 0x21ec);
+
+		/* Physical ordered set for PCIe */
+		writel(0x02, priv->mmio + 0x45c0);
+		writel(0x83, priv->mmio + 0x45c4);
+		writel(0x03, priv->mmio + 0x45c8);
+		writel(0x43, priv->mmio + 0x45cc);
+		writel(0x00, priv->mmio + 0x45d0);
+		writel(0xbc, priv->mmio + 0x45d4);
+
+		/* Boost pre-emphasis */
+		writel(0xaa, priv->mmio + 0x21b8);
+		writel(0xaa, priv->mmio + 0x31b8);
+	} else if (priv->phy_type == PHY_TYPE_USB3) {
+		/*
+		 * Disable PHY Lane 1 which isn't needed
+		 * for USB3 to reduce power consumption.
+		 */
+		/* Lane 1 cdr power down */
+		writel(0x09, priv->mmio + 0x3148);
+
+		/* Lane 1 rx bias disable */
+		writel(0x01, priv->mmio + 0x21cc);
+
+		/* Lane 1 cdr disable */
+		writel(0x08, priv->mmio + 0x30c4);
+		writel(0x08, priv->mmio + 0x20f4);
+
+		/* Lane 1 rx lock disable and tx bias disable */
+		writel(0x12, priv->mmio + 0x3150);
+
+		/* Lane 1 rx termination disable, and tx_cmenb disable */
+		writel(0x04, priv->mmio + 0x3080);
+
+		/* Lane 1 tx termination disable */
+		writel(0x1d, priv->mmio + 0x3090);
+
+		/* Lane 1 tx driver disable */
+		writel(0x50, priv->mmio + 0x21c4);
+		writel(0x10, priv->mmio + 0x2050);
+
+		/* Lane 1 txldo_refsel disable */
+		writel(0x81, priv->mmio + 0x31a8);
+
+		/* Lane 1 txdetrx_en disable */
+		writel(0x00, priv->mmio + 0x31e8);
+
+		/* Lane 1 rxcm_en disable */
+		writel(0x08, priv->mmio + 0x30c0);
+
+		/* Adjust Lane 0 Rx interface timing */
+		writel(0x20, priv->mmio + 0x20ac);
+
+		/* Set and enable SSC */
+		switch (rate) {
+		case 24000000:
+			/* Set SSC rate to 31.25KHz */
+			reg = readl(priv->mmio + 0x2108);
+			reg = (reg & ~0xf) | 0x1;
+			writel(reg, priv->mmio + 0x2108);
+			ssc_en = true;
+			break;
+		case 25000000:
+			/* Set SSC rate to 32.55KHz */
+			reg = readl(priv->mmio + 0x2108);
+			reg = (reg & ~0xf) | 0x6;
+			writel(reg, priv->mmio + 0x2108);
+			ssc_en = true;
+			break;
+		default:
+			dev_warn(priv->dev,
+				 "failed to set SSC on rate: %lu\n", rate);
+			break;
+		}
+
+		if (ssc_en) {
+			/* Enable SSC */
+			reg = readl(priv->mmio + 0x2120);
+			reg &= ~BIT(4);
+			writel(reg, priv->mmio + 0x2120);
+
+			reg = readl(priv->mmio + 0x2000);
+			reg &= ~0x6;
+			writel(reg, priv->mmio + 0x2000);
+		}
+
+		/*
+		 * Tuning Tx:
+		 * offset 0x21b8 bit[7:4]: lane 0 TX driver swing
+		 * tuning bits with weight, "1111" represents the
+		 * largest swing and "0000" the smallest.
+		 */
+		reg = readl(priv->mmio + 0x21b8);
+		reg = (reg & ~0xf0) | 0xe0;
+		writel(reg, priv->mmio + 0x21b8);
+
+		/*
+		 * Tuning Rx for RJTL:
+		 * Decrease CDR Chump Bump current.
+		 */
+		reg = readl(priv->mmio + 0x20c8);
+		reg = (reg & ~0x6) | BIT(1);
+		writel(reg, priv->mmio + 0x20c8);
+		reg = readl(priv->mmio + 0x2150);
+		reg |= BIT(2);
+		writel(reg, priv->mmio + 0x2150);
+	} else {
+		dev_err(priv->dev, "failed to cfg incompatible PHY type\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rk1808_combphy_low_power_control(struct rockchip_combphy_priv *priv,
+					    bool en)
+{
+	if (priv->phy_type != PHY_TYPE_USB3) {
+		/* turn off pcie phy pd */
+		writel(0x08400840, priv->mmio + 0x0);
+		writel(0x03030303, priv->mmio + 0x8);
+
+		/* enter PCIe phy low power mode */
+		writel(0x36, priv->mmio + 0x2150);
+		writel(0x36, priv->mmio + 0x3150);
+		writel(0x02, priv->mmio + 0x21e8);
+		writel(0x02, priv->mmio + 0x31e8);
+		writel(0x0c, priv->mmio + 0x2080);
+		writel(0x0c, priv->mmio + 0x3080);
+		writel(0x08, priv->mmio + 0x20c0);
+		writel(0x08, priv->mmio + 0x30c0);
+		writel(0x08, priv->mmio + 0x2058);
+
+		writel(0x10, priv->mmio + 0x2044);
+		writel(0x10, priv->mmio + 0x21a8);
+		writel(0x10, priv->mmio + 0x31a8);
+		writel(0x08, priv->mmio + 0x2058);
+		writel(0x08, priv->mmio + 0x3058);
+		writel(0x40, priv->mmio + 0x205c);
+		writel(0x40, priv->mmio + 0x305c);
+		writel(0x08, priv->mmio + 0x2184);
+		writel(0x08, priv->mmio + 0x3184);
+		writel(0x00, priv->mmio + 0x2150);
+		writel(0x00, priv->mmio + 0x3150);
+		writel(0x10, priv->mmio + 0x20e0);
+		writel(0x00, priv->mmio + 0x21e8);
+		writel(0x00, priv->mmio + 0x31e8);
+
+		return 0;
+	}
+
+	if (en) {
+		/* Lane 0 tx_biasen disable */
+		writel(0x36, priv->mmio + 0x2150);
+
+		/* Lane 0 txdetrx_en disable */
+		writel(0x02, priv->mmio + 0x21e8);
+
+		/* Lane 0 tx_cmenb disable */
+		writel(0x0c, priv->mmio + 0x2080);
+
+		/* Lane 0 rxcm_en disable */
+		writel(0x08, priv->mmio + 0x20c0);
+
+		/* Lane 0 and Lane 1 bg_pwrdn */
+		writel(0x10, priv->mmio + 0x2044);
+
+		/* Lane 0 and Lane 1 rcomp_osenseampen disable */
+		writel(0x08, priv->mmio + 0x2058);
+
+		/* Lane 0 txldo_refsel disable and LDO disable */
+		writel(0x91, priv->mmio + 0x21a8);
+
+		/* Lane 1 LDO disable */
+		writel(0x91, priv->mmio + 0x31a8);
+	} else {
+		/* Lane 0 tx_biasen enable */
+		writel(0x76, priv->mmio + 0x2150);
+
+		/* Lane 0 txdetrx_en enable */
+		writel(0x02, priv->mmio + 0x21e8);
+
+		/* Lane 0 tx_cmenb enable */
+		writel(0x08, priv->mmio + 0x2080);
+
+		/* Lane 0 rxcm_en enable */
+		writel(0x18, priv->mmio + 0x20c0);
+
+		/* Lane 0 and Lane 1 bg_pwrdn */
+		writel(0x00, priv->mmio + 0x2044);
+
+		/* Lane 0 and Lane 1 rcomp_osenseampen enable */
+		writel(0x28, priv->mmio + 0x2058);
+
+		/* Lane 0 txldo_refsel enable and LDO enable */
+		writel(0x01, priv->mmio + 0x21a8);
+
+		/* Lane 1 LDO enable */
+		writel(0x81, priv->mmio + 0x31a8);
+	}
+
+	return 0;
+}
+
+static const struct rockchip_combphy_cfg rk1808_combphy_cfgs = {
+	.grfcfg	= {
+		.pipe_l1_sel	= { 0x0000, 15, 11, 0x00, 0x1f },
+		.pipe_l1_set	= { 0x0008, 13, 8, 0x00, 0x13 },
+		.pipe_l1rxterm_sel = { 0x0000, 12, 12, 0x0, 0x1 },
+		.pipe_l1pd_sel	= { 0x0000, 11, 11, 0x0, 0x1},
+		.pipe_l1pd_p3	= { 0x0008, 9, 8, 0x0, 0x3 },
+		.pipe_l0rxterm_sel = { 0x0000, 7, 7, 0x0, 0x1 },
+		.pipe_l0pd_sel	= { 0x0000, 6, 6, 0x0, 0x1 },
+		.pipe_l0pd_p3	= { 0x0008, 1, 0, 0x0, 0x3 },
+		.pipe_clk_sel	= { 0x0000, 3, 3, 0x0, 0x1 },
+		.pipe_clk_set	= { 0x0004, 7, 6, 0x1, 0x0 },
+		.pipe_rate_sel	= { 0x0000, 2, 2, 0x0, 0x1 },
+		.pipe_rate_set	= { 0x0004, 5, 4, 0x0, 0x1 },
+		.pipe_mode_sel	= { 0x0000, 1, 1, 0x0, 0x1 },
+		.pipe_mode_set	= { 0x0004, 3, 2, 0x0, 0x1 },
+		.pipe_txrx_sel	= { 0x0004, 15, 8, 0x10, 0x2f },
+		.pipe_txrx_set	= { 0x0008, 15, 14, 0x0, 0x3 },
+		.pipe_l1rxterm_set = { 0x0008, 10, 10, 0x0, 0x1 },
+		.pipe_l0rxterm_set = { 0x0008, 2, 2, 0x0, 0x1 },
+		.pipe_l0rxelec_set = { 0x0008, 6, 6, 0x0, 0x1 },
+		.pipe_width_sel	= { 0x0000, 0, 0, 0x0, 0x1 },
+		.pipe_width_set	= { 0x0004, 1, 0, 0x2, 0x0 },
+		.pipe_usb3_sel	= { 0x000c, 0, 0, 0x0, 0x1 },
+		.pipe_pll_lock	= { 0x0034, 14, 14, 0x0, 0x1 },
+		.pipe_status_l0	= { 0x0034, 7, 7, 0x1, 0x0 },
+		.u3_port_disable = { 0x0434, 0, 0, 0, 1},
+		.u3_port_num	= { 0x0434, 15, 12, 0, 1},
+	},
+	.combphy_cfg		= rk1808_combphy_cfg,
+	.combphy_low_power_ctrl	= rk1808_combphy_low_power_control,
+};
+
+static const struct of_device_id rockchip_combphy_of_match[] = {
+	{
+		.compatible = "rockchip,rk1808-combphy",
+		.data = &rk1808_combphy_cfgs,
+	},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_combphy_of_match);
+
+static struct platform_driver rockchip_combphy_driver = {
+	.probe	= rockchip_combphy_probe,
+	.remove = rockchip_combphy_remove,
+	.driver = {
+		.name = "rockchip-combphy",
+		.of_match_table = rockchip_combphy_of_match,
+	},
+};
+module_platform_driver(rockchip_combphy_driver);
+
+MODULE_AUTHOR("Rockchip Inc.");
+MODULE_DESCRIPTION("Rockchip USB3.0 and PCIE COMBPHY driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

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

* [PATCH 3/6] PCI: dwc: Skip allocating own MSI domain if using external MSI domain
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci, devicetree, William Wu, Simon Xue,
	linux-rockchip, Shawn Lin

On some platform, external MSI domain is using instead of the one
created by designware driver. For instance, if using GIC-V3-ITS
as a MSI domain, we only need set msi-map in the devicetree but
never need any bit in the designware driver to handle MSI stuff.
So skip allocating its own MSI domain for that case.

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Simon Xue <xxm@rock-chips.com>
---

 drivers/pci/controller/dwc/pcie-designware-host.c | 10 +++++++++-
 drivers/pci/controller/dwc/pcie-designware.h      |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 395feb8..e78d094 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -257,6 +257,10 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 	struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
 
+	/* Rely on the external MSI domain */
+	if (pp->msi_ext)
+		return 0;
+
 	pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
 					       &dw_pcie_msi_domain_ops, pp);
 	if (!pp->irq_domain) {
@@ -278,6 +282,9 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
 
 void dw_pcie_free_msi(struct pcie_port *pp)
 {
+	if (pp->msi_ext)
+		return;
+
 	if (pp->msi_irq) {
 		irq_set_chained_handler(pp->msi_irq, NULL);
 		irq_set_handler_data(pp->msi_irq, NULL);
@@ -413,7 +420,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	if (ret)
 		pci->num_viewport = 2;
 
-	if (pci_msi_enabled()) {
+	if (pci_msi_enabled() &&
+	    !pp->msi_ext) {
 		/*
 		 * If a specific SoC driver needs to change the
 		 * default number of vectors, it needs to implement
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index a22ea59..eeafa52 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -201,6 +201,7 @@ struct pcie_port {
 	u32			irq_mask[MAX_MSI_CTRLS];
 	struct pci_bus		*root_bus;
 	raw_spinlock_t		lock;
+	int			msi_ext;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
-- 
1.9.1




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

* [PATCH 3/6] PCI: dwc: Skip allocating own MSI domain if using external MSI domain
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	Shawn Lin, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu

On some platform, external MSI domain is using instead of the one
created by designware driver. For instance, if using GIC-V3-ITS
as a MSI domain, we only need set msi-map in the devicetree but
never need any bit in the designware driver to handle MSI stuff.
So skip allocating its own MSI domain for that case.

Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Signed-off-by: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---

 drivers/pci/controller/dwc/pcie-designware-host.c | 10 +++++++++-
 drivers/pci/controller/dwc/pcie-designware.h      |  1 +
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 395feb8..e78d094 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -257,6 +257,10 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
 	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 	struct fwnode_handle *fwnode = of_node_to_fwnode(pci->dev->of_node);
 
+	/* Rely on the external MSI domain */
+	if (pp->msi_ext)
+		return 0;
+
 	pp->irq_domain = irq_domain_create_linear(fwnode, pp->num_vectors,
 					       &dw_pcie_msi_domain_ops, pp);
 	if (!pp->irq_domain) {
@@ -278,6 +282,9 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
 
 void dw_pcie_free_msi(struct pcie_port *pp)
 {
+	if (pp->msi_ext)
+		return;
+
 	if (pp->msi_irq) {
 		irq_set_chained_handler(pp->msi_irq, NULL);
 		irq_set_handler_data(pp->msi_irq, NULL);
@@ -413,7 +420,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	if (ret)
 		pci->num_viewport = 2;
 
-	if (pci_msi_enabled()) {
+	if (pci_msi_enabled() &&
+	    !pp->msi_ext) {
 		/*
 		 * If a specific SoC driver needs to change the
 		 * default number of vectors, it needs to implement
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index a22ea59..eeafa52 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -201,6 +201,7 @@ struct pcie_port {
 	u32			irq_mask[MAX_MSI_CTRLS];
 	struct pci_bus		*root_bus;
 	raw_spinlock_t		lock;
+	int			msi_ext;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 };
 
-- 
1.9.1

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

* [PATCH 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci, devicetree, William Wu, Simon Xue,
	linux-rockchip, Shawn Lin

From: Simon Xue <xxm@rock-chips.com>

Signed-off-by: Simon Xue <xxm@rock-chips.com>
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

 .../devicetree/bindings/pci/rockchip-dw-pcie.yaml  | 132 +++++++++++++++++++++
 1 file changed, 132 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml

diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
new file mode 100644
index 0000000..c5205f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
@@ -0,0 +1,132 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/rockchip-dw-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DesignWare based PCIe RC controller on Rockchip SoCs
+
+maintainers:
+        - Shawn Lin <shawn.lin@rock-chips.com>
+        - Simon Xue <xxm@rock-chips.com>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk1808-pcie
+      - snps,dw-pcie
+
+  reg:
+    maxItems: 2
+
+  clocks:
+    items:
+      - description: High speed clock for PCIe
+      - description: Low speed clock for PCIe
+      - description: AHB clock for PCIe
+      - description: APB clock for PCIe
+      - description: Auxiliary clock for PCIe
+
+  clock-names:
+    items:
+      - const: hsclk
+      - const: lsclk
+      - const: aclk
+      - const: pclk
+      - const: sclk-aux
+
+  resets:
+    items:
+      - description: PCIe niu high reset line
+      - description: PCIe niu low reset line
+      - description: PCIe grf reset line
+      - description: PCIe control reset line
+      - description: PCIe control powerup reset line
+      - description: PCIe control master reset line
+      - description: PCIe control slave reset line
+      - description: PCIe control dbi reset line
+      - description: PCIe control button reset line
+      - description: PCIe control power engine reset line
+      - description: PCIe control core reset line
+      - description: PCIe control non-sticky reset line
+      - description: PCIe control sticky reset line
+      - description: PCIe control power reset line
+      - description: PCIe niu ahb reset line
+      - description: PCIe niu apb reset line
+
+  reset-names:
+    items:
+      - const: niu-h
+      - const: niu-l
+      - const: grf-p
+      - const: ctl-p
+      - const: ctl-powerup
+      - const: ctl-mst-a
+      - const: ctl-slv-a
+      - const: ctl-dbi-a
+      - const: ctl-button
+      - const: ctl-pe
+      - const: ctl-core
+      - const: ctl-nsticky
+      - const: ctl-sticky
+      - const: ctl-pwr
+      - const: ctl-niu-a
+      - const: ctl-niu-p
+
+  rockchip,usbpciegrf:
+    items:
+      - description: The grf for COMBPHY configuration and state registers.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - msi-map
+  - num-lanes
+  - phys
+  - phy-names
+  - resets
+  - reset-names
+  - rockchip,usbpciegrf
+
+additionalProperties: false
+
+examples:
+  - |
+    usb_pcie_grf: syscon@fe040000 {
+        compatible = "rockchip,usb-pcie-grf", "syscon";
+        reg = <0x0 0xfe040000 0x0 0x1000>;
+    };
+
+    pcie0: pcie@fc400000 {
+        compatible = "rockchip,rk1808-pcie", "snps,dw-pcie";
+        reg = <0x0 0xfc000000 0x0 0x400000>,
+              <0x0 0xfc400000 0x0 0x10000>;
+        clocks = <&cru HSCLK_PCIE>, <&cru LSCLK_PCIE>,
+                 <&cru ACLK_PCIE>, <&cru PCLK_PCIE>,
+                 <&cru SCLK_PCIE_AUX>;
+        clock-names = "hsclk", "lsclk",
+                      "aclk", "pclk",
+                      "sclk-aux";
+        msi-map = <0x0 &its 0x0 0x1000>;
+        num-lanes = <2>;
+        phys = <&combphy PHY_TYPE_PCIE>;
+        phy-names = "pcie-phy";
+        resets = <&cru SRST_PCIE_NIU_H>, <&cru SRST_PCIE_NIU_L>,
+                 <&cru SRST_PCIEGRF_P>, <&cru SRST_PCIECTL_P>,
+                 <&cru SRST_PCIECTL_POWERUP>, <&cru SRST_PCIECTL_MST_A>,
+                 <&cru SRST_PCIECTL_SLV_A>, <&cru SRST_PCIECTL_DBI_A>,
+                 <&cru SRST_PCIECTL_BUTTON>, <&cru SRST_PCIECTL_PE>,
+                 <&cru SRST_PCIECTL_CORE>, <&cru SRST_PCIECTL_NSTICKY>,
+                 <&cru SRST_PCIECTL_STICKY>, <&cru SRST_PCIECTL_PWR>,
+                 <&cru SRST_PCIE_NIU_A>, <&cru SRST_PCIE_NIU_P>;
+        reset-names = "niu-h", "niu-l", "grf-p", "ctl-p",
+                      "ctl-powerup", "ctl-mst-a", "ctl-slv-a",
+                      "ctl-dbi-a", "ctl-button", "ctl-pe",
+                      "ctl-core", "ctl-nsticky", "ctl-sticky",
+                      "ctl-pwr", "ctl-niu-a", "ctl-niu-p";
+        rockchip,usbpciegrf = <&usb_pcie_grf>;
+    };
+
+...
-- 
1.9.1




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

* [PATCH 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller
@ 2020-01-14  7:22   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:22 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	Shawn Lin, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu

From: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

Signed-off-by: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---

 .../devicetree/bindings/pci/rockchip-dw-pcie.yaml  | 132 +++++++++++++++++++++
 1 file changed, 132 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml

diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
new file mode 100644
index 0000000..c5205f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
@@ -0,0 +1,132 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/rockchip-dw-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DesignWare based PCIe RC controller on Rockchip SoCs
+
+maintainers:
+        - Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+        - Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk1808-pcie
+      - snps,dw-pcie
+
+  reg:
+    maxItems: 2
+
+  clocks:
+    items:
+      - description: High speed clock for PCIe
+      - description: Low speed clock for PCIe
+      - description: AHB clock for PCIe
+      - description: APB clock for PCIe
+      - description: Auxiliary clock for PCIe
+
+  clock-names:
+    items:
+      - const: hsclk
+      - const: lsclk
+      - const: aclk
+      - const: pclk
+      - const: sclk-aux
+
+  resets:
+    items:
+      - description: PCIe niu high reset line
+      - description: PCIe niu low reset line
+      - description: PCIe grf reset line
+      - description: PCIe control reset line
+      - description: PCIe control powerup reset line
+      - description: PCIe control master reset line
+      - description: PCIe control slave reset line
+      - description: PCIe control dbi reset line
+      - description: PCIe control button reset line
+      - description: PCIe control power engine reset line
+      - description: PCIe control core reset line
+      - description: PCIe control non-sticky reset line
+      - description: PCIe control sticky reset line
+      - description: PCIe control power reset line
+      - description: PCIe niu ahb reset line
+      - description: PCIe niu apb reset line
+
+  reset-names:
+    items:
+      - const: niu-h
+      - const: niu-l
+      - const: grf-p
+      - const: ctl-p
+      - const: ctl-powerup
+      - const: ctl-mst-a
+      - const: ctl-slv-a
+      - const: ctl-dbi-a
+      - const: ctl-button
+      - const: ctl-pe
+      - const: ctl-core
+      - const: ctl-nsticky
+      - const: ctl-sticky
+      - const: ctl-pwr
+      - const: ctl-niu-a
+      - const: ctl-niu-p
+
+  rockchip,usbpciegrf:
+    items:
+      - description: The grf for COMBPHY configuration and state registers.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - msi-map
+  - num-lanes
+  - phys
+  - phy-names
+  - resets
+  - reset-names
+  - rockchip,usbpciegrf
+
+additionalProperties: false
+
+examples:
+  - |
+    usb_pcie_grf: syscon@fe040000 {
+        compatible = "rockchip,usb-pcie-grf", "syscon";
+        reg = <0x0 0xfe040000 0x0 0x1000>;
+    };
+
+    pcie0: pcie@fc400000 {
+        compatible = "rockchip,rk1808-pcie", "snps,dw-pcie";
+        reg = <0x0 0xfc000000 0x0 0x400000>,
+              <0x0 0xfc400000 0x0 0x10000>;
+        clocks = <&cru HSCLK_PCIE>, <&cru LSCLK_PCIE>,
+                 <&cru ACLK_PCIE>, <&cru PCLK_PCIE>,
+                 <&cru SCLK_PCIE_AUX>;
+        clock-names = "hsclk", "lsclk",
+                      "aclk", "pclk",
+                      "sclk-aux";
+        msi-map = <0x0 &its 0x0 0x1000>;
+        num-lanes = <2>;
+        phys = <&combphy PHY_TYPE_PCIE>;
+        phy-names = "pcie-phy";
+        resets = <&cru SRST_PCIE_NIU_H>, <&cru SRST_PCIE_NIU_L>,
+                 <&cru SRST_PCIEGRF_P>, <&cru SRST_PCIECTL_P>,
+                 <&cru SRST_PCIECTL_POWERUP>, <&cru SRST_PCIECTL_MST_A>,
+                 <&cru SRST_PCIECTL_SLV_A>, <&cru SRST_PCIECTL_DBI_A>,
+                 <&cru SRST_PCIECTL_BUTTON>, <&cru SRST_PCIECTL_PE>,
+                 <&cru SRST_PCIECTL_CORE>, <&cru SRST_PCIECTL_NSTICKY>,
+                 <&cru SRST_PCIECTL_STICKY>, <&cru SRST_PCIECTL_PWR>,
+                 <&cru SRST_PCIE_NIU_A>, <&cru SRST_PCIE_NIU_P>;
+        reset-names = "niu-h", "niu-l", "grf-p", "ctl-p",
+                      "ctl-powerup", "ctl-mst-a", "ctl-slv-a",
+                      "ctl-dbi-a", "ctl-button", "ctl-pe",
+                      "ctl-core", "ctl-nsticky", "ctl-sticky",
+                      "ctl-pwr", "ctl-niu-a", "ctl-niu-p";
+        rockchip,usbpciegrf = <&usb_pcie_grf>;
+    };
+
+...
-- 
1.9.1

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

* [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-14  7:25   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:25 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci, devicetree, William Wu, Simon Xue,
	linux-rockchip, Shawn Lin

From: Simon Xue <xxm@rock-chips.com>

Signed-off-by: Simon Xue <xxm@rock-chips.com>
Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

 drivers/pci/controller/dwc/Kconfig            |   9 +
 drivers/pci/controller/dwc/Makefile           |   1 +
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 441 ++++++++++++++++++++++++++
 3 files changed, 451 insertions(+)
 create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c

diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 0830dfc..9160264 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -82,6 +82,15 @@ config PCIE_DW_PLAT_EP
 	  order to enable device-specific features PCI_DW_PLAT_EP must be
 	  selected.
 
+config PCIE_DW_ROCKCHIP
+	bool "Rockchip DesignWare PCIe controller"
+	select PCIE_DW
+	select PCIE_DW_HOST
+	depends on ARCH_ROCKCHIP
+	depends on OF
+	help
+	  Enables support for the DW PCIe controller in the Rockchip SoC.
+
 config PCI_EXYNOS
 	bool "Samsung Exynos PCIe controller"
 	depends on SOC_EXYNOS5440 || COMPILE_TEST
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 8a637cf..cb4857f 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
 obj-$(CONFIG_PCI_MESON) += pci-meson.o
 obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
 obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
+obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie-dw-rockchip.o
 
 # The following drivers are for devices that use the generic ACPI
 # pci_root.c driver but don't support standard ECAM config access.
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
new file mode 100644
index 0000000..dbc2667
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for Rockchip SoCs
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *		http://www.rock-chips.com
+ *
+ * Author: Simon Xue <xxm@rock-chips.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "pcie-designware.h"
+
+/*
+ * The upper 16 bits of PCIE_CLIENT_CONFIG are a write
+ * mask for the lower 16 bits.  This allows atomic updates
+ * of the register without locking.
+ */
+#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
+#define HIWORD_UPDATE_BIT(val)	HIWORD_UPDATE(val, val)
+
+#define to_rockchip_pcie(x) dev_get_drvdata((x)->dev)
+
+#define PCIE_CLIENT_RC_MODE		HIWORD_UPDATE_BIT(0x40)
+#define PCIE_CLIENT_ENABLE_LTSSM	HIWORD_UPDATE_BIT(0xc)
+#define PCIE_PHY_LINKUP			BIT(0)
+#define PCIE_DATA_LINKUP		BIT(1)
+#define PCIE_LTSSM_STATE_MASK		GENMASK(15, 10)
+#define PCIE_LTSSM_STATE_SHIFT		10
+#define PCIE_L0S_ENTRY			0x11
+#define PCIE_CLIENT_GENERAL_CONTROL	0x0
+#define PCIE_CLIENT_GENERAL_DEBUG	0x104
+#define SUB_PHY_MODE_PCIE_RC		0x0
+#define SUB_PHY_MODE_PCIE_EP		0x1
+
+
+struct reset_bulk_data	{
+	const char *id;
+	struct reset_control *rst;
+};
+
+struct rockchip_pcie {
+	struct dw_pcie			*pci;
+	void __iomem			*dbi_base;
+	void __iomem			*apb_base;
+	struct phy			*phy;
+	struct clk_bulk_data		*clks;
+	unsigned int			clk_cnt;
+	struct reset_bulk_data		*rsts;
+	struct gpio_desc		*rst_gpio;
+	struct pcie_port		pp;
+	struct regmap			*usb_pcie_grf;
+	enum dw_pcie_device_mode	mode;
+	int				sub_phy_mode;
+};
+
+struct rockchip_pcie_of_data {
+	enum dw_pcie_device_mode	mode;
+};
+
+static inline int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip,
+					  u32 reg)
+{
+	return readl(rockchip->apb_base + reg);
+}
+
+static inline void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip,
+					    u32 reg, u32 val)
+{
+	writel(val, rockchip->apb_base + reg);
+}
+
+static inline void rockchip_pcie_set_mode(struct rockchip_pcie *rockchip)
+{
+	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_GENERAL_CONTROL,
+				 PCIE_CLIENT_RC_MODE);
+}
+
+static inline void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
+{
+	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_GENERAL_CONTROL,
+				 PCIE_CLIENT_ENABLE_LTSSM);
+}
+
+static int rockchip_pcie_link_up(struct dw_pcie *pci)
+{
+	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
+	u32 val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_GENERAL_DEBUG);
+	u32 state = (val & PCIE_LTSSM_STATE_MASK) >> PCIE_LTSSM_STATE_SHIFT;
+
+	if ((val & PCIE_PHY_LINKUP) &&
+	    (val & PCIE_DATA_LINKUP) &&
+	    state == PCIE_L0S_ENTRY)
+		return 1;
+
+	return 0;
+}
+
+static void rockchip_pcie_establish_link(struct dw_pcie *pci)
+{
+	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
+
+	if (dw_pcie_link_up(pci)) {
+		dev_err(pci->dev, "link already up\n");
+		return;
+	}
+
+	/* Reset device */
+	gpiod_set_value_cansleep(rockchip->rst_gpio, 0);
+	msleep(100);
+	gpiod_set_value_cansleep(rockchip->rst_gpio, 1);
+
+	rockchip_pcie_enable_ltssm(rockchip);
+}
+
+static int rockchip_pcie_host_init(struct pcie_port *pp)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+	dw_pcie_setup_rc(pp);
+
+	rockchip_pcie_establish_link(pci);
+	dw_pcie_wait_for_link(pci);
+
+	return 0;
+}
+
+static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
+	.host_init = rockchip_pcie_host_init,
+};
+
+static int rk_add_pcie_port(struct rockchip_pcie *rockchip)
+{
+	int ret;
+	struct dw_pcie *pci = rockchip->pci;
+	struct pcie_port *pp = &pci->pp;
+	struct device *dev = pci->dev;
+
+	pp->ops = &rockchip_pcie_host_ops;
+
+	if (device_property_read_bool(dev, "msi-map"))
+		pp->msi_ext = 1;
+
+	rockchip_pcie_set_mode(rockchip);
+
+	ret = dw_pcie_host_init(pp);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void rockchip_pcie_clk_deinit(struct rockchip_pcie *rockchip)
+{
+	clk_bulk_disable(rockchip->clk_cnt, rockchip->clks);
+	clk_bulk_unprepare(rockchip->clk_cnt, rockchip->clks);
+}
+
+static int rockchip_pcie_clk_init(struct rockchip_pcie *rockchip)
+{
+	struct device *dev = rockchip->pci->dev;
+	struct property *prop;
+	const char *name;
+	int i = 0, ret, count;
+
+	count = of_property_count_strings(dev->of_node, "clock-names");
+	if (count < 1)
+		return -ENODEV;
+
+	rockchip->clks = devm_kcalloc(dev, count,
+				     sizeof(struct clk_bulk_data),
+				     GFP_KERNEL);
+	if (!rockchip->clks)
+		return -ENOMEM;
+
+	rockchip->clk_cnt = count;
+
+	of_property_for_each_string(dev->of_node, "clock-names",
+				    prop, name) {
+		rockchip->clks[i].id = name;
+		if (!rockchip->clks[i].id)
+			return -ENOMEM;
+		i++;
+	}
+
+	ret = devm_clk_bulk_get(dev, count, rockchip->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare(count, rockchip->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_enable(count, rockchip->clks);
+	if (ret) {
+		clk_bulk_unprepare(count, rockchip->clks);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_pcie_resource_get(struct platform_device *pdev,
+				      struct rockchip_pcie *rockchip)
+{
+	struct resource *dbi_base;
+	struct resource *apb_base;
+
+	dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"pcie-dbi");
+	if (!dbi_base)
+		return -ENODEV;
+
+	rockchip->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
+	if (IS_ERR(rockchip->dbi_base))
+		return PTR_ERR(rockchip->dbi_base);
+
+	rockchip->pci->dbi_base = rockchip->dbi_base;
+
+	apb_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"pcie-apb");
+	if (!apb_base)
+		return -ENODEV;
+
+	rockchip->apb_base = devm_ioremap_resource(&pdev->dev, apb_base);
+	if (IS_ERR(rockchip->apb_base))
+		return PTR_ERR(rockchip->apb_base);
+
+	rockchip->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
+						    GPIOD_OUT_HIGH);
+	if (IS_ERR(rockchip->rst_gpio))
+		return PTR_ERR(rockchip->rst_gpio);
+
+	return 0;
+}
+
+static int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip)
+{
+	int ret;
+	struct device *dev = rockchip->pci->dev;
+
+	rockchip->phy = devm_phy_get(dev, "pcie-phy");
+	if (IS_ERR(rockchip->phy)) {
+		if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER)
+			dev_info(dev, "missing phy\n");
+		return PTR_ERR(rockchip->phy);
+	}
+
+	rockchip->sub_phy_mode = rockchip->mode == DW_PCIE_RC_TYPE ?
+			SUB_PHY_MODE_PCIE_RC : SUB_PHY_MODE_PCIE_EP;
+
+	ret = phy_set_mode_ext(rockchip->phy, PHY_MODE_PCIE,
+			       rockchip->sub_phy_mode);
+	if (ret)
+		return ret;
+
+	ret = phy_init(rockchip->phy);
+	if (ret < 0)
+		return ret;
+
+	phy_power_on(rockchip->phy);
+
+	return 0;
+}
+
+static int rockchip_pcie_reset_control_release(struct rockchip_pcie *rockchip)
+{
+	struct device *dev = rockchip->pci->dev;
+	struct property *prop;
+	const char *name;
+	int ret, count, i = 0;
+
+	count = of_property_count_strings(dev->of_node, "reset-names");
+	if (count < 1)
+		return -ENODEV;
+
+	rockchip->rsts = devm_kcalloc(dev, count,
+				     sizeof(struct reset_bulk_data),
+				     GFP_KERNEL);
+	if (!rockchip->rsts)
+		return -ENOMEM;
+
+	of_property_for_each_string(dev->of_node, "reset-names",
+				    prop, name) {
+		rockchip->rsts[i].id = name;
+		if (!rockchip->rsts[i].id)
+			return -ENOMEM;
+		i++;
+	}
+
+	for (i = 0; i < count; i++) {
+		rockchip->rsts[i].rst = devm_reset_control_get_exclusive(dev,
+						rockchip->rsts[i].id);
+		if (IS_ERR_OR_NULL(rockchip->rsts[i].rst)) {
+			dev_err(dev, "failed to get %s\n",
+				rockchip->clks[i].id);
+			return -PTR_ERR(rockchip->rsts[i].rst);
+		}
+	}
+
+	for (i = 0; i < count; i++) {
+		ret = reset_control_deassert(rockchip->rsts[i].rst);
+		if (ret) {
+			dev_err(dev, "failed to release %s\n",
+				rockchip->rsts[i].id);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_pcie_reset_grant_ctrl(struct rockchip_pcie *rockchip,
+					  bool enable)
+{
+	int ret;
+	u32 val = HIWORD_UPDATE(BIT(2), 0); /* Write mask bit */
+
+	if (enable)
+		val |= BIT(2);
+
+	ret = regmap_write(rockchip->usb_pcie_grf, 0x0, val);
+	return ret;
+}
+
+static const struct rockchip_pcie_of_data rockchip_rc_of_data = {
+	.mode = DW_PCIE_RC_TYPE,
+};
+
+static const struct of_device_id rockchip_pcie_of_match[] = {
+	{
+		.compatible = "rockchip,rk1808-pcie",
+		.data = &rockchip_rc_of_data,
+	},
+	{ /* sentinel */ },
+};
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+	.link_up = rockchip_pcie_link_up,
+};
+
+static int rockchip_pcie_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_pcie *rockchip;
+	struct dw_pcie *pci;
+	int ret;
+	const struct of_device_id *match;
+	const struct rockchip_pcie_of_data *data;
+	enum dw_pcie_device_mode mode;
+
+	match = of_match_device(rockchip_pcie_of_match, dev);
+	if (!match)
+		return -EINVAL;
+
+	data = (struct rockchip_pcie_of_data *)match->data;
+	mode = (enum dw_pcie_device_mode)data->mode;
+
+	rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
+	if (!rockchip)
+		return -ENOMEM;
+
+	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+	if (!pci)
+		return -ENOMEM;
+
+	pci->dev = dev;
+	pci->ops = &dw_pcie_ops;
+
+	rockchip->mode = mode;
+	rockchip->pci = pci;
+
+	ret = rockchip_pcie_resource_get(pdev, rockchip);
+	if (ret)
+		return ret;
+
+	ret = rockchip_pcie_phy_init(rockchip);
+	if (ret)
+		return ret;
+
+	ret = rockchip_pcie_reset_control_release(rockchip);
+	if (ret)
+		return ret;
+
+	rockchip->usb_pcie_grf =
+		syscon_regmap_lookup_by_phandle(dev->of_node,
+						"rockchip,usbpciegrf");
+	if (IS_ERR(rockchip->usb_pcie_grf))
+		return PTR_ERR(rockchip->usb_pcie_grf);
+
+	ret = rockchip_pcie_clk_init(rockchip);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, rockchip);
+
+	ret = rockchip_pcie_reset_grant_ctrl(rockchip, true);
+	if (ret)
+		goto deinit_clk;
+
+//	if (rockchip->mode == DW_PCIE_RC_TYPE)
+//		ret = rk_add_pcie_port(rockchip);
+	ret = rockchip->mode == DW_PCIE_RC_TYPE ?
+		rk_add_pcie_port(rockchip) : -EINVAL;
+
+	if (ret)
+		goto deinit_clk;
+
+	ret = rockchip_pcie_reset_grant_ctrl(rockchip, false);
+	if (ret)
+		goto deinit_clk;
+
+	return 0;
+
+deinit_clk:
+	rockchip_pcie_clk_deinit(rockchip);
+
+	return ret;
+}
+
+MODULE_DEVICE_TABLE(of, rockchip_pcie_of_match);
+
+static struct platform_driver rockchip_pcie_driver = {
+	.driver = {
+		.name	= "rk-pcie",
+		.of_match_table = rockchip_pcie_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = rockchip_pcie_probe,
+};
+
+builtin_platform_driver(rockchip_pcie_driver);
-- 
1.9.1




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

* [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-14  7:25   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:25 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	Shawn Lin, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu

From: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

Signed-off-by: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---

 drivers/pci/controller/dwc/Kconfig            |   9 +
 drivers/pci/controller/dwc/Makefile           |   1 +
 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 441 ++++++++++++++++++++++++++
 3 files changed, 451 insertions(+)
 create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c

diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 0830dfc..9160264 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -82,6 +82,15 @@ config PCIE_DW_PLAT_EP
 	  order to enable device-specific features PCI_DW_PLAT_EP must be
 	  selected.
 
+config PCIE_DW_ROCKCHIP
+	bool "Rockchip DesignWare PCIe controller"
+	select PCIE_DW
+	select PCIE_DW_HOST
+	depends on ARCH_ROCKCHIP
+	depends on OF
+	help
+	  Enables support for the DW PCIe controller in the Rockchip SoC.
+
 config PCI_EXYNOS
 	bool "Samsung Exynos PCIe controller"
 	depends on SOC_EXYNOS5440 || COMPILE_TEST
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 8a637cf..cb4857f 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
 obj-$(CONFIG_PCI_MESON) += pci-meson.o
 obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
 obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
+obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie-dw-rockchip.o
 
 # The following drivers are for devices that use the generic ACPI
 # pci_root.c driver but don't support standard ECAM config access.
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
new file mode 100644
index 0000000..dbc2667
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for Rockchip SoCs
+ *
+ * Copyright (C) 2018 Rockchip Electronics Co., Ltd.
+ *		http://www.rock-chips.com
+ *
+ * Author: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "pcie-designware.h"
+
+/*
+ * The upper 16 bits of PCIE_CLIENT_CONFIG are a write
+ * mask for the lower 16 bits.  This allows atomic updates
+ * of the register without locking.
+ */
+#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
+#define HIWORD_UPDATE_BIT(val)	HIWORD_UPDATE(val, val)
+
+#define to_rockchip_pcie(x) dev_get_drvdata((x)->dev)
+
+#define PCIE_CLIENT_RC_MODE		HIWORD_UPDATE_BIT(0x40)
+#define PCIE_CLIENT_ENABLE_LTSSM	HIWORD_UPDATE_BIT(0xc)
+#define PCIE_PHY_LINKUP			BIT(0)
+#define PCIE_DATA_LINKUP		BIT(1)
+#define PCIE_LTSSM_STATE_MASK		GENMASK(15, 10)
+#define PCIE_LTSSM_STATE_SHIFT		10
+#define PCIE_L0S_ENTRY			0x11
+#define PCIE_CLIENT_GENERAL_CONTROL	0x0
+#define PCIE_CLIENT_GENERAL_DEBUG	0x104
+#define SUB_PHY_MODE_PCIE_RC		0x0
+#define SUB_PHY_MODE_PCIE_EP		0x1
+
+
+struct reset_bulk_data	{
+	const char *id;
+	struct reset_control *rst;
+};
+
+struct rockchip_pcie {
+	struct dw_pcie			*pci;
+	void __iomem			*dbi_base;
+	void __iomem			*apb_base;
+	struct phy			*phy;
+	struct clk_bulk_data		*clks;
+	unsigned int			clk_cnt;
+	struct reset_bulk_data		*rsts;
+	struct gpio_desc		*rst_gpio;
+	struct pcie_port		pp;
+	struct regmap			*usb_pcie_grf;
+	enum dw_pcie_device_mode	mode;
+	int				sub_phy_mode;
+};
+
+struct rockchip_pcie_of_data {
+	enum dw_pcie_device_mode	mode;
+};
+
+static inline int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip,
+					  u32 reg)
+{
+	return readl(rockchip->apb_base + reg);
+}
+
+static inline void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip,
+					    u32 reg, u32 val)
+{
+	writel(val, rockchip->apb_base + reg);
+}
+
+static inline void rockchip_pcie_set_mode(struct rockchip_pcie *rockchip)
+{
+	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_GENERAL_CONTROL,
+				 PCIE_CLIENT_RC_MODE);
+}
+
+static inline void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
+{
+	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_GENERAL_CONTROL,
+				 PCIE_CLIENT_ENABLE_LTSSM);
+}
+
+static int rockchip_pcie_link_up(struct dw_pcie *pci)
+{
+	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
+	u32 val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_GENERAL_DEBUG);
+	u32 state = (val & PCIE_LTSSM_STATE_MASK) >> PCIE_LTSSM_STATE_SHIFT;
+
+	if ((val & PCIE_PHY_LINKUP) &&
+	    (val & PCIE_DATA_LINKUP) &&
+	    state == PCIE_L0S_ENTRY)
+		return 1;
+
+	return 0;
+}
+
+static void rockchip_pcie_establish_link(struct dw_pcie *pci)
+{
+	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
+
+	if (dw_pcie_link_up(pci)) {
+		dev_err(pci->dev, "link already up\n");
+		return;
+	}
+
+	/* Reset device */
+	gpiod_set_value_cansleep(rockchip->rst_gpio, 0);
+	msleep(100);
+	gpiod_set_value_cansleep(rockchip->rst_gpio, 1);
+
+	rockchip_pcie_enable_ltssm(rockchip);
+}
+
+static int rockchip_pcie_host_init(struct pcie_port *pp)
+{
+	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+	dw_pcie_setup_rc(pp);
+
+	rockchip_pcie_establish_link(pci);
+	dw_pcie_wait_for_link(pci);
+
+	return 0;
+}
+
+static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
+	.host_init = rockchip_pcie_host_init,
+};
+
+static int rk_add_pcie_port(struct rockchip_pcie *rockchip)
+{
+	int ret;
+	struct dw_pcie *pci = rockchip->pci;
+	struct pcie_port *pp = &pci->pp;
+	struct device *dev = pci->dev;
+
+	pp->ops = &rockchip_pcie_host_ops;
+
+	if (device_property_read_bool(dev, "msi-map"))
+		pp->msi_ext = 1;
+
+	rockchip_pcie_set_mode(rockchip);
+
+	ret = dw_pcie_host_init(pp);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void rockchip_pcie_clk_deinit(struct rockchip_pcie *rockchip)
+{
+	clk_bulk_disable(rockchip->clk_cnt, rockchip->clks);
+	clk_bulk_unprepare(rockchip->clk_cnt, rockchip->clks);
+}
+
+static int rockchip_pcie_clk_init(struct rockchip_pcie *rockchip)
+{
+	struct device *dev = rockchip->pci->dev;
+	struct property *prop;
+	const char *name;
+	int i = 0, ret, count;
+
+	count = of_property_count_strings(dev->of_node, "clock-names");
+	if (count < 1)
+		return -ENODEV;
+
+	rockchip->clks = devm_kcalloc(dev, count,
+				     sizeof(struct clk_bulk_data),
+				     GFP_KERNEL);
+	if (!rockchip->clks)
+		return -ENOMEM;
+
+	rockchip->clk_cnt = count;
+
+	of_property_for_each_string(dev->of_node, "clock-names",
+				    prop, name) {
+		rockchip->clks[i].id = name;
+		if (!rockchip->clks[i].id)
+			return -ENOMEM;
+		i++;
+	}
+
+	ret = devm_clk_bulk_get(dev, count, rockchip->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_prepare(count, rockchip->clks);
+	if (ret)
+		return ret;
+
+	ret = clk_bulk_enable(count, rockchip->clks);
+	if (ret) {
+		clk_bulk_unprepare(count, rockchip->clks);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_pcie_resource_get(struct platform_device *pdev,
+				      struct rockchip_pcie *rockchip)
+{
+	struct resource *dbi_base;
+	struct resource *apb_base;
+
+	dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"pcie-dbi");
+	if (!dbi_base)
+		return -ENODEV;
+
+	rockchip->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
+	if (IS_ERR(rockchip->dbi_base))
+		return PTR_ERR(rockchip->dbi_base);
+
+	rockchip->pci->dbi_base = rockchip->dbi_base;
+
+	apb_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"pcie-apb");
+	if (!apb_base)
+		return -ENODEV;
+
+	rockchip->apb_base = devm_ioremap_resource(&pdev->dev, apb_base);
+	if (IS_ERR(rockchip->apb_base))
+		return PTR_ERR(rockchip->apb_base);
+
+	rockchip->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
+						    GPIOD_OUT_HIGH);
+	if (IS_ERR(rockchip->rst_gpio))
+		return PTR_ERR(rockchip->rst_gpio);
+
+	return 0;
+}
+
+static int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip)
+{
+	int ret;
+	struct device *dev = rockchip->pci->dev;
+
+	rockchip->phy = devm_phy_get(dev, "pcie-phy");
+	if (IS_ERR(rockchip->phy)) {
+		if (PTR_ERR(rockchip->phy) != -EPROBE_DEFER)
+			dev_info(dev, "missing phy\n");
+		return PTR_ERR(rockchip->phy);
+	}
+
+	rockchip->sub_phy_mode = rockchip->mode == DW_PCIE_RC_TYPE ?
+			SUB_PHY_MODE_PCIE_RC : SUB_PHY_MODE_PCIE_EP;
+
+	ret = phy_set_mode_ext(rockchip->phy, PHY_MODE_PCIE,
+			       rockchip->sub_phy_mode);
+	if (ret)
+		return ret;
+
+	ret = phy_init(rockchip->phy);
+	if (ret < 0)
+		return ret;
+
+	phy_power_on(rockchip->phy);
+
+	return 0;
+}
+
+static int rockchip_pcie_reset_control_release(struct rockchip_pcie *rockchip)
+{
+	struct device *dev = rockchip->pci->dev;
+	struct property *prop;
+	const char *name;
+	int ret, count, i = 0;
+
+	count = of_property_count_strings(dev->of_node, "reset-names");
+	if (count < 1)
+		return -ENODEV;
+
+	rockchip->rsts = devm_kcalloc(dev, count,
+				     sizeof(struct reset_bulk_data),
+				     GFP_KERNEL);
+	if (!rockchip->rsts)
+		return -ENOMEM;
+
+	of_property_for_each_string(dev->of_node, "reset-names",
+				    prop, name) {
+		rockchip->rsts[i].id = name;
+		if (!rockchip->rsts[i].id)
+			return -ENOMEM;
+		i++;
+	}
+
+	for (i = 0; i < count; i++) {
+		rockchip->rsts[i].rst = devm_reset_control_get_exclusive(dev,
+						rockchip->rsts[i].id);
+		if (IS_ERR_OR_NULL(rockchip->rsts[i].rst)) {
+			dev_err(dev, "failed to get %s\n",
+				rockchip->clks[i].id);
+			return -PTR_ERR(rockchip->rsts[i].rst);
+		}
+	}
+
+	for (i = 0; i < count; i++) {
+		ret = reset_control_deassert(rockchip->rsts[i].rst);
+		if (ret) {
+			dev_err(dev, "failed to release %s\n",
+				rockchip->rsts[i].id);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int rockchip_pcie_reset_grant_ctrl(struct rockchip_pcie *rockchip,
+					  bool enable)
+{
+	int ret;
+	u32 val = HIWORD_UPDATE(BIT(2), 0); /* Write mask bit */
+
+	if (enable)
+		val |= BIT(2);
+
+	ret = regmap_write(rockchip->usb_pcie_grf, 0x0, val);
+	return ret;
+}
+
+static const struct rockchip_pcie_of_data rockchip_rc_of_data = {
+	.mode = DW_PCIE_RC_TYPE,
+};
+
+static const struct of_device_id rockchip_pcie_of_match[] = {
+	{
+		.compatible = "rockchip,rk1808-pcie",
+		.data = &rockchip_rc_of_data,
+	},
+	{ /* sentinel */ },
+};
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+	.link_up = rockchip_pcie_link_up,
+};
+
+static int rockchip_pcie_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_pcie *rockchip;
+	struct dw_pcie *pci;
+	int ret;
+	const struct of_device_id *match;
+	const struct rockchip_pcie_of_data *data;
+	enum dw_pcie_device_mode mode;
+
+	match = of_match_device(rockchip_pcie_of_match, dev);
+	if (!match)
+		return -EINVAL;
+
+	data = (struct rockchip_pcie_of_data *)match->data;
+	mode = (enum dw_pcie_device_mode)data->mode;
+
+	rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
+	if (!rockchip)
+		return -ENOMEM;
+
+	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+	if (!pci)
+		return -ENOMEM;
+
+	pci->dev = dev;
+	pci->ops = &dw_pcie_ops;
+
+	rockchip->mode = mode;
+	rockchip->pci = pci;
+
+	ret = rockchip_pcie_resource_get(pdev, rockchip);
+	if (ret)
+		return ret;
+
+	ret = rockchip_pcie_phy_init(rockchip);
+	if (ret)
+		return ret;
+
+	ret = rockchip_pcie_reset_control_release(rockchip);
+	if (ret)
+		return ret;
+
+	rockchip->usb_pcie_grf =
+		syscon_regmap_lookup_by_phandle(dev->of_node,
+						"rockchip,usbpciegrf");
+	if (IS_ERR(rockchip->usb_pcie_grf))
+		return PTR_ERR(rockchip->usb_pcie_grf);
+
+	ret = rockchip_pcie_clk_init(rockchip);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, rockchip);
+
+	ret = rockchip_pcie_reset_grant_ctrl(rockchip, true);
+	if (ret)
+		goto deinit_clk;
+
+//	if (rockchip->mode == DW_PCIE_RC_TYPE)
+//		ret = rk_add_pcie_port(rockchip);
+	ret = rockchip->mode == DW_PCIE_RC_TYPE ?
+		rk_add_pcie_port(rockchip) : -EINVAL;
+
+	if (ret)
+		goto deinit_clk;
+
+	ret = rockchip_pcie_reset_grant_ctrl(rockchip, false);
+	if (ret)
+		goto deinit_clk;
+
+	return 0;
+
+deinit_clk:
+	rockchip_pcie_clk_deinit(rockchip);
+
+	return ret;
+}
+
+MODULE_DEVICE_TABLE(of, rockchip_pcie_of_match);
+
+static struct platform_driver rockchip_pcie_driver = {
+	.driver = {
+		.name	= "rk-pcie",
+		.of_match_table = rockchip_pcie_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = rockchip_pcie_probe,
+};
+
+builtin_platform_driver(rockchip_pcie_driver);
-- 
1.9.1

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

* [PATCH 6/6] MAINTAINERS: Update PCIe drivers for Rockchip
@ 2020-01-14  7:25   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:25 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci, devicetree, William Wu, Simon Xue,
	linux-rockchip, Shawn Lin

Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
---

 MAINTAINERS | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4b11d43..f95a85d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12956,11 +12956,13 @@ F:	drivers/pci/controller/dwc/*qcom*
 
 PCIE DRIVER FOR ROCKCHIP
 M:	Shawn Lin <shawn.lin@rock-chips.com>
+M:	Simon Xue <xxm@rock-chips.com>
 L:	linux-pci@vger.kernel.org
 L:	linux-rockchip@lists.infradead.org
 S:	Maintained
-F:	Documentation/devicetree/bindings/pci/rockchip-pcie*
+F:	Documentation/devicetree/bindings/pci/*rockchip*
 F:	drivers/pci/controller/pcie-rockchip*
+F:	drivers/pci/controller/dwc/*rockchip*
 
 PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC
 M:	Linus Walleij <linus.walleij@linaro.org>
-- 
1.9.1




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

* [PATCH 6/6] MAINTAINERS: Update PCIe drivers for Rockchip
@ 2020-01-14  7:25   ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-14  7:25 UTC (permalink / raw)
  To: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: Jingoo Han, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, William Wu, Simon Xue,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Shawn Lin

Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---

 MAINTAINERS | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 4b11d43..f95a85d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12956,11 +12956,13 @@ F:	drivers/pci/controller/dwc/*qcom*
 
 PCIE DRIVER FOR ROCKCHIP
 M:	Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+M:	Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
 L:	linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
 L:	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
 S:	Maintained
-F:	Documentation/devicetree/bindings/pci/rockchip-pcie*
+F:	Documentation/devicetree/bindings/pci/*rockchip*
 F:	drivers/pci/controller/pcie-rockchip*
+F:	drivers/pci/controller/dwc/*rockchip*
 
 PCI DRIVER FOR V3 SEMICONDUCTOR V360EPC
 M:	Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
-- 
1.9.1

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

* Re: [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP
@ 2020-01-14 23:43     ` Rob Herring
  0 siblings, 0 replies; 28+ messages in thread
From: Rob Herring @ 2020-01-14 23:43 UTC (permalink / raw)
  To: Shawn Lin
  Cc: Heiko Stuebner, Lorenzo Pieralisi, Kishon Vijay Abraham I,
	Bjorn Helgaas, Jingoo Han, linux-pci, devicetree, William Wu,
	Simon Xue, linux-rockchip

On Tue, Jan 14, 2020 at 03:22:55PM +0800, Shawn Lin wrote:
> This IP could supports USB3.0 and PCIe.
> 
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> 
> ---
> 
>  .../bindings/phy/rockchip,inno-combophy.yaml       | 84 ++++++++++++++++++++++
>  1 file changed, 84 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml

Fails 'make dt_binding_check':

/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml: 
ignoring, error in schema: properties: rockchip,combphygrf
Documentation/devicetree/bindings/display/simple-framebuffer.example.dts:21.16-37.11: 
Warning (chosen_node_is_root): /example-0/chosen: chosen node must be at root node
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml: 
properties:rockchip,combphygrf: {'items': [{'description': 'The grf for 
COMBPHY configuration and state registers.'}]} is not valid under any of 
the given schemas (Possible causes of the failure):
	
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml: 
properties:rockchip,combphygrf: 'description' is a required property


> 
> diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
> new file mode 100644
> index 0000000..d647ab3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
> @@ -0,0 +1,84 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/rockchip,inno-combophy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip USB3.0/PCI-e combo phy
> +
> +maintainers:
> +        - Shawn Lin <shawn.lin@rock-chips.com>
> +        - William Wu <william.wu@rock-chips.com>

2 space indent.

> +
> +properties:
> +  "#phy-cells":
> +    const: 1
> +
> +  compatible:
> +    enum:
> +      - rockchip,rk1808-combphy
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    items:
> +      - description: PLL reference clock
> +
> +  clock-names:
> +    items:
> +      - const: refclk
> +
> +  resets:
> +    items:
> +      - description: OTG unit reset line
> +      - description: POR unit reset line
> +      - description: APB interface reset line
> +      - description: PIPE unit reset line
> +
> +  reset-names:
> +    items:
> +      - const: otg-rst
> +      - const: combphy-por
> +      - const: combphy-apb
> +      - const: combphy-pipe
> +
> +  rockchip,combphygrf:
> +    items:
> +      - description: The grf for COMBPHY configuration and state registers.
> +
> +required:
> +  - "#phy-cells"
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - resets
> +  - reset-names
> +  - rockchip,combphygrf
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    combphy_grf: syscon@fe018000 {
> +        compatible = "rockchip,usb3phy-grf", "syscon";
> +        reg = <0x0 0xfe018000 0x0 0x8000>;
> +    };
> +
> +    combphy: phy@ff380000 {
> +        compatible = "rockchip,rk1808-combphy";
> +        reg = <0x0 0xff380000 0x0 0x10000>;
> +        #phy-cells = <1>;
> +        clocks = <&cru SCLK_PCIEPHY_REF>;
> +        clock-names = "refclk";
> +        assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
> +        assigned-clock-rates = <25000000>;
> +        resets = <&cru SRST_USB3_OTG_A>, <&cru SRST_PCIEPHY_POR>,
> +                 <&cru SRST_PCIEPHY_P>, <&cru SRST_PCIEPHY_PIPE>;
> +        reset-names = "otg-rst", "combphy-por",
> +                      "combphy-apb", "combphy-pipe";
> +        rockchip,combphygrf = <&combphy_grf>;
> +    };
> +
> +...
> -- 
> 1.9.1
> 
> 
> 

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

* Re: [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP
@ 2020-01-14 23:43     ` Rob Herring
  0 siblings, 0 replies; 28+ messages in thread
From: Rob Herring @ 2020-01-14 23:43 UTC (permalink / raw)
  To: Shawn Lin
  Cc: Heiko Stuebner, Lorenzo Pieralisi, Kishon Vijay Abraham I,
	Bjorn Helgaas, Jingoo Han, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, William Wu, Simon Xue,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, Jan 14, 2020 at 03:22:55PM +0800, Shawn Lin wrote:
> This IP could supports USB3.0 and PCIe.
> 
> Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> 
> ---
> 
>  .../bindings/phy/rockchip,inno-combophy.yaml       | 84 ++++++++++++++++++++++
>  1 file changed, 84 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml

Fails 'make dt_binding_check':

/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml: 
ignoring, error in schema: properties: rockchip,combphygrf
Documentation/devicetree/bindings/display/simple-framebuffer.example.dts:21.16-37.11: 
Warning (chosen_node_is_root): /example-0/chosen: chosen node must be at root node
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml: 
properties:rockchip,combphygrf: {'items': [{'description': 'The grf for 
COMBPHY configuration and state registers.'}]} is not valid under any of 
the given schemas (Possible causes of the failure):
	
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml: 
properties:rockchip,combphygrf: 'description' is a required property


> 
> diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
> new file mode 100644
> index 0000000..d647ab3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
> @@ -0,0 +1,84 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/phy/rockchip,inno-combophy.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Rockchip USB3.0/PCI-e combo phy
> +
> +maintainers:
> +        - Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> +        - William Wu <william.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

2 space indent.

> +
> +properties:
> +  "#phy-cells":
> +    const: 1
> +
> +  compatible:
> +    enum:
> +      - rockchip,rk1808-combphy
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    items:
> +      - description: PLL reference clock
> +
> +  clock-names:
> +    items:
> +      - const: refclk
> +
> +  resets:
> +    items:
> +      - description: OTG unit reset line
> +      - description: POR unit reset line
> +      - description: APB interface reset line
> +      - description: PIPE unit reset line
> +
> +  reset-names:
> +    items:
> +      - const: otg-rst
> +      - const: combphy-por
> +      - const: combphy-apb
> +      - const: combphy-pipe
> +
> +  rockchip,combphygrf:
> +    items:
> +      - description: The grf for COMBPHY configuration and state registers.
> +
> +required:
> +  - "#phy-cells"
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - resets
> +  - reset-names
> +  - rockchip,combphygrf
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    combphy_grf: syscon@fe018000 {
> +        compatible = "rockchip,usb3phy-grf", "syscon";
> +        reg = <0x0 0xfe018000 0x0 0x8000>;
> +    };
> +
> +    combphy: phy@ff380000 {
> +        compatible = "rockchip,rk1808-combphy";
> +        reg = <0x0 0xff380000 0x0 0x10000>;
> +        #phy-cells = <1>;
> +        clocks = <&cru SCLK_PCIEPHY_REF>;
> +        clock-names = "refclk";
> +        assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
> +        assigned-clock-rates = <25000000>;
> +        resets = <&cru SRST_USB3_OTG_A>, <&cru SRST_PCIEPHY_POR>,
> +                 <&cru SRST_PCIEPHY_P>, <&cru SRST_PCIEPHY_PIPE>;
> +        reset-names = "otg-rst", "combphy-por",
> +                      "combphy-apb", "combphy-pipe";
> +        rockchip,combphygrf = <&combphy_grf>;
> +    };
> +
> +...
> -- 
> 1.9.1
> 
> 
> 

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

* Re: [PATCH 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller
  2020-01-14  7:22   ` Shawn Lin
  (?)
@ 2020-01-15  0:05   ` Rob Herring
  -1 siblings, 0 replies; 28+ messages in thread
From: Rob Herring @ 2020-01-15  0:05 UTC (permalink / raw)
  To: Shawn Lin
  Cc: Heiko Stuebner, Lorenzo Pieralisi, Kishon Vijay Abraham I,
	Bjorn Helgaas, Jingoo Han, linux-pci, devicetree, William Wu,
	Simon Xue, linux-rockchip

On Tue, Jan 14, 2020 at 03:22:58PM +0800, Shawn Lin wrote:
> From: Simon Xue <xxm@rock-chips.com>
> 
> Signed-off-by: Simon Xue <xxm@rock-chips.com>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> ---
> 
>  .../devicetree/bindings/pci/rockchip-dw-pcie.yaml  | 132 +++++++++++++++++++++
>  1 file changed, 132 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml

/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml: 
properties:rockchip,usbpciegrf: {'items': [{'description': 'The grf for 
COMBPHY configuration and state registers.'}]} is not valid under any of 
the given schemas (Possible causes of the failure):
	
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml: 
properties:rockchip,usbpciegrf: 'description' is a required property

> 
> diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
> new file mode 100644
> index 0000000..c5205f6
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
> @@ -0,0 +1,132 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/rockchip-dw-pcie.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: DesignWare based PCIe RC controller on Rockchip SoCs
> +
> +maintainers:
> +        - Shawn Lin <shawn.lin@rock-chips.com>
> +        - Simon Xue <xxm@rock-chips.com>

indent 2 spaces.

> +

You need to reference pci-bus.yaml.

> +properties:
> +  compatible:
> +    enum:
> +      - rockchip,rk1808-pcie
> +      - snps,dw-pcie

This means the compatible is one of these 2 strings.

It's also going to be a problem because it will match on all DTs with 
'snps,dw-pcie'. Look at some of the 'arm,primecell' schema for how to 
avoid that with 'select'.

> +
> +  reg:
> +    maxItems: 2
> +
> +  clocks:
> +    items:
> +      - description: High speed clock for PCIe
> +      - description: Low speed clock for PCIe
> +      - description: AHB clock for PCIe
> +      - description: APB clock for PCIe
> +      - description: Auxiliary clock for PCIe
> +
> +  clock-names:
> +    items:
> +      - const: hsclk
> +      - const: lsclk
> +      - const: aclk
> +      - const: pclk
> +      - const: sclk-aux
> +
> +  resets:
> +    items:
> +      - description: PCIe niu high reset line
> +      - description: PCIe niu low reset line
> +      - description: PCIe grf reset line
> +      - description: PCIe control reset line
> +      - description: PCIe control powerup reset line
> +      - description: PCIe control master reset line
> +      - description: PCIe control slave reset line
> +      - description: PCIe control dbi reset line
> +      - description: PCIe control button reset line
> +      - description: PCIe control power engine reset line
> +      - description: PCIe control core reset line
> +      - description: PCIe control non-sticky reset line
> +      - description: PCIe control sticky reset line
> +      - description: PCIe control power reset line
> +      - description: PCIe niu ahb reset line
> +      - description: PCIe niu apb reset line
> +
> +  reset-names:
> +    items:
> +      - const: niu-h
> +      - const: niu-l
> +      - const: grf-p
> +      - const: ctl-p
> +      - const: ctl-powerup
> +      - const: ctl-mst-a
> +      - const: ctl-slv-a
> +      - const: ctl-dbi-a
> +      - const: ctl-button
> +      - const: ctl-pe
> +      - const: ctl-core
> +      - const: ctl-nsticky
> +      - const: ctl-sticky
> +      - const: ctl-pwr
> +      - const: ctl-niu-a
> +      - const: ctl-niu-p
> +
> +  rockchip,usbpciegrf:
> +    items:
> +      - description: The grf for COMBPHY configuration and state registers.
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - msi-map
> +  - num-lanes
> +  - phys
> +  - phy-names
> +  - resets
> +  - reset-names
> +  - rockchip,usbpciegrf
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    usb_pcie_grf: syscon@fe040000 {
> +        compatible = "rockchip,usb-pcie-grf", "syscon";
> +        reg = <0x0 0xfe040000 0x0 0x1000>;
> +    };
> +
> +    pcie0: pcie@fc400000 {
> +        compatible = "rockchip,rk1808-pcie", "snps,dw-pcie";
> +        reg = <0x0 0xfc000000 0x0 0x400000>,
> +              <0x0 0xfc400000 0x0 0x10000>;
> +        clocks = <&cru HSCLK_PCIE>, <&cru LSCLK_PCIE>,
> +                 <&cru ACLK_PCIE>, <&cru PCLK_PCIE>,
> +                 <&cru SCLK_PCIE_AUX>;
> +        clock-names = "hsclk", "lsclk",
> +                      "aclk", "pclk",
> +                      "sclk-aux";
> +        msi-map = <0x0 &its 0x0 0x1000>;
> +        num-lanes = <2>;
> +        phys = <&combphy PHY_TYPE_PCIE>;
> +        phy-names = "pcie-phy";
> +        resets = <&cru SRST_PCIE_NIU_H>, <&cru SRST_PCIE_NIU_L>,
> +                 <&cru SRST_PCIEGRF_P>, <&cru SRST_PCIECTL_P>,
> +                 <&cru SRST_PCIECTL_POWERUP>, <&cru SRST_PCIECTL_MST_A>,
> +                 <&cru SRST_PCIECTL_SLV_A>, <&cru SRST_PCIECTL_DBI_A>,
> +                 <&cru SRST_PCIECTL_BUTTON>, <&cru SRST_PCIECTL_PE>,
> +                 <&cru SRST_PCIECTL_CORE>, <&cru SRST_PCIECTL_NSTICKY>,
> +                 <&cru SRST_PCIECTL_STICKY>, <&cru SRST_PCIECTL_PWR>,
> +                 <&cru SRST_PCIE_NIU_A>, <&cru SRST_PCIE_NIU_P>;
> +        reset-names = "niu-h", "niu-l", "grf-p", "ctl-p",
> +                      "ctl-powerup", "ctl-mst-a", "ctl-slv-a",
> +                      "ctl-dbi-a", "ctl-button", "ctl-pe",
> +                      "ctl-core", "ctl-nsticky", "ctl-sticky",
> +                      "ctl-pwr", "ctl-niu-a", "ctl-niu-p";
> +        rockchip,usbpciegrf = <&usb_pcie_grf>;

You are missing a number of common, required PCI properties.

> +    };
> +
> +...
> -- 
> 1.9.1
> 
> 
> 

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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
  2020-01-14  7:25   ` Shawn Lin
  (?)
@ 2020-01-15 17:24   ` Bjorn Helgaas
  2020-01-16  0:14       ` Shawn Lin
  -1 siblings, 1 reply; 28+ messages in thread
From: Bjorn Helgaas @ 2020-01-15 17:24 UTC (permalink / raw)
  To: Shawn Lin
  Cc: Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Jingoo Han, linux-pci, devicetree,
	William Wu, Simon Xue, linux-rockchip

Follow subject line convention.

On Tue, Jan 14, 2020 at 03:25:01PM +0800, Shawn Lin wrote:
> From: Simon Xue <xxm@rock-chips.com>

Needs a commit log.  Please describe the relationship with the
existing drivers/pci/controller/pcie-rockchip-host.c.  Are they for
different devices?  Does this supercede the other?

> Signed-off-by: Simon Xue <xxm@rock-chips.com>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> ---
> 
>  drivers/pci/controller/dwc/Kconfig            |   9 +
>  drivers/pci/controller/dwc/Makefile           |   1 +
>  drivers/pci/controller/dwc/pcie-dw-rockchip.c | 441 ++++++++++++++++++++++++++
>  3 files changed, 451 insertions(+)
>  create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c
> 
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index 0830dfc..9160264 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -82,6 +82,15 @@ config PCIE_DW_PLAT_EP
>  	  order to enable device-specific features PCI_DW_PLAT_EP must be
>  	  selected.
>  
> +config PCIE_DW_ROCKCHIP
> +	bool "Rockchip DesignWare PCIe controller"
> +	select PCIE_DW
> +	select PCIE_DW_HOST
> +	depends on ARCH_ROCKCHIP
> +	depends on OF
> +	help
> +	  Enables support for the DW PCIe controller in the Rockchip SoC.

A user needs to be able to tell whether to enable
CONFIG_PCIE_ROCKCHIP_HOST or CONFIG_PCIE_DW_ROCKCHIP.  Is there an
endpoint driver coming?  Should this be named PCIE_DW_ROCKCHIP_HOST?

> +	ret = rockchip_pcie_reset_grant_ctrl(rockchip, true);
> +	if (ret)
> +		goto deinit_clk;
> +
> +//	if (rockchip->mode == DW_PCIE_RC_TYPE)
> +//		ret = rk_add_pcie_port(rockchip);

Remove commented-out code.  I do like an "if" statement better than
the complicated assignment/ternary thing below, though.

> +	ret = rockchip->mode == DW_PCIE_RC_TYPE ?
> +		rk_add_pcie_port(rockchip) : -EINVAL;
> +
> +	if (ret)
> +		goto deinit_clk;

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

* Re: [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP【请注意,邮件由linux-rockchip-bounces+shawn.lin=rock-chips.com@lists.infradead.org代发】
  2020-01-14 23:43     ` Rob Herring
@ 2020-01-16  0:03       ` Shawn Lin
  -1 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-16  0:03 UTC (permalink / raw)
  To: Rob Herring
  Cc: shawn.lin, devicetree, Lorenzo Pieralisi, Heiko Stuebner,
	linux-rockchip, Jingoo Han, Kishon Vijay Abraham I, William Wu,
	linux-pci, Bjorn Helgaas, Simon Xue



On 2020/1/15 7:43, Rob Herring wrote:
> On Tue, Jan 14, 2020 at 03:22:55PM +0800, Shawn Lin wrote:
>> This IP could supports USB3.0 and PCIe.
>>
>> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
>>
>> ---
>>
>>   .../bindings/phy/rockchip,inno-combophy.yaml       | 84 ++++++++++++++++++++++
>>   1 file changed, 84 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
> 
> Fails 'make dt_binding_check':
> 
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml:
> ignoring, error in schema: properties: rockchip,combphygrf
> Documentation/devicetree/bindings/display/simple-framebuffer.example.dts:21.16-37.11:
> Warning (chosen_node_is_root): /example-0/chosen: chosen node must be at root node
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml:
> properties:rockchip,combphygrf: {'items': [{'description': 'The grf for
> COMBPHY configuration and state registers.'}]} is not valid under any of
> the given schemas (Possible causes of the failure):
> 	
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml:
> properties:rockchip,combphygrf: 'description' is a required property
> 

Thanks Rob, will fix them in v2.

> 
>>
>> diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
>> new file mode 100644
>> index 0000000..d647ab3
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
>> @@ -0,0 +1,84 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/phy/rockchip,inno-combophy.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Rockchip USB3.0/PCI-e combo phy
>> +
>> +maintainers:
>> +        - Shawn Lin <shawn.lin@rock-chips.com>
>> +        - William Wu <william.wu@rock-chips.com>
> 
> 2 space indent.
> 
>> +
>> +properties:
>> +  "#phy-cells":
>> +    const: 1
>> +
>> +  compatible:
>> +    enum:
>> +      - rockchip,rk1808-combphy
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  clocks:
>> +    items:
>> +      - description: PLL reference clock
>> +
>> +  clock-names:
>> +    items:
>> +      - const: refclk
>> +
>> +  resets:
>> +    items:
>> +      - description: OTG unit reset line
>> +      - description: POR unit reset line
>> +      - description: APB interface reset line
>> +      - description: PIPE unit reset line
>> +
>> +  reset-names:
>> +    items:
>> +      - const: otg-rst
>> +      - const: combphy-por
>> +      - const: combphy-apb
>> +      - const: combphy-pipe
>> +
>> +  rockchip,combphygrf:
>> +    items:
>> +      - description: The grf for COMBPHY configuration and state registers.
>> +
>> +required:
>> +  - "#phy-cells"
>> +  - compatible
>> +  - reg
>> +  - clocks
>> +  - clock-names
>> +  - resets
>> +  - reset-names
>> +  - rockchip,combphygrf
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    combphy_grf: syscon@fe018000 {
>> +        compatible = "rockchip,usb3phy-grf", "syscon";
>> +        reg = <0x0 0xfe018000 0x0 0x8000>;
>> +    };
>> +
>> +    combphy: phy@ff380000 {
>> +        compatible = "rockchip,rk1808-combphy";
>> +        reg = <0x0 0xff380000 0x0 0x10000>;
>> +        #phy-cells = <1>;
>> +        clocks = <&cru SCLK_PCIEPHY_REF>;
>> +        clock-names = "refclk";
>> +        assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
>> +        assigned-clock-rates = <25000000>;
>> +        resets = <&cru SRST_USB3_OTG_A>, <&cru SRST_PCIEPHY_POR>,
>> +                 <&cru SRST_PCIEPHY_P>, <&cru SRST_PCIEPHY_PIPE>;
>> +        reset-names = "otg-rst", "combphy-por",
>> +                      "combphy-apb", "combphy-pipe";
>> +        rockchip,combphygrf = <&combphy_grf>;
>> +    };
>> +
>> +...
>> -- 
>> 1.9.1
>>
>>
>>
> 
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
> 
> 
> 



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

* Re: [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP【请注意,邮件由linux-rockchip-bounces+shawn.lin=rock-chips.com@lists.infradead.org代发】
@ 2020-01-16  0:03       ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-16  0:03 UTC (permalink / raw)
  To: Rob Herring
  Cc: shawn.lin-TNX95d0MmH7DzftRWevZcw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Lorenzo Pieralisi,
	Heiko Stuebner, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Jingoo Han, Kishon Vijay Abraham I, William Wu,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, Bjorn Helgaas, Simon Xue



On 2020/1/15 7:43, Rob Herring wrote:
> On Tue, Jan 14, 2020 at 03:22:55PM +0800, Shawn Lin wrote:
>> This IP could supports USB3.0 and PCIe.
>>
>> Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>>
>> ---
>>
>>   .../bindings/phy/rockchip,inno-combophy.yaml       | 84 ++++++++++++++++++++++
>>   1 file changed, 84 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
> 
> Fails 'make dt_binding_check':
> 
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml:
> ignoring, error in schema: properties: rockchip,combphygrf
> Documentation/devicetree/bindings/display/simple-framebuffer.example.dts:21.16-37.11:
> Warning (chosen_node_is_root): /example-0/chosen: chosen node must be at root node
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml:
> properties:rockchip,combphygrf: {'items': [{'description': 'The grf for
> COMBPHY configuration and state registers.'}]} is not valid under any of
> the given schemas (Possible causes of the failure):
> 	
> /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml:
> properties:rockchip,combphygrf: 'description' is a required property
> 

Thanks Rob, will fix them in v2.

> 
>>
>> diff --git a/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
>> new file mode 100644
>> index 0000000..d647ab3
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
>> @@ -0,0 +1,84 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/phy/rockchip,inno-combophy.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: Rockchip USB3.0/PCI-e combo phy
>> +
>> +maintainers:
>> +        - Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>> +        - William Wu <william.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> 
> 2 space indent.
> 
>> +
>> +properties:
>> +  "#phy-cells":
>> +    const: 1
>> +
>> +  compatible:
>> +    enum:
>> +      - rockchip,rk1808-combphy
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  clocks:
>> +    items:
>> +      - description: PLL reference clock
>> +
>> +  clock-names:
>> +    items:
>> +      - const: refclk
>> +
>> +  resets:
>> +    items:
>> +      - description: OTG unit reset line
>> +      - description: POR unit reset line
>> +      - description: APB interface reset line
>> +      - description: PIPE unit reset line
>> +
>> +  reset-names:
>> +    items:
>> +      - const: otg-rst
>> +      - const: combphy-por
>> +      - const: combphy-apb
>> +      - const: combphy-pipe
>> +
>> +  rockchip,combphygrf:
>> +    items:
>> +      - description: The grf for COMBPHY configuration and state registers.
>> +
>> +required:
>> +  - "#phy-cells"
>> +  - compatible
>> +  - reg
>> +  - clocks
>> +  - clock-names
>> +  - resets
>> +  - reset-names
>> +  - rockchip,combphygrf
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> +  - |
>> +    combphy_grf: syscon@fe018000 {
>> +        compatible = "rockchip,usb3phy-grf", "syscon";
>> +        reg = <0x0 0xfe018000 0x0 0x8000>;
>> +    };
>> +
>> +    combphy: phy@ff380000 {
>> +        compatible = "rockchip,rk1808-combphy";
>> +        reg = <0x0 0xff380000 0x0 0x10000>;
>> +        #phy-cells = <1>;
>> +        clocks = <&cru SCLK_PCIEPHY_REF>;
>> +        clock-names = "refclk";
>> +        assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
>> +        assigned-clock-rates = <25000000>;
>> +        resets = <&cru SRST_USB3_OTG_A>, <&cru SRST_PCIEPHY_POR>,
>> +                 <&cru SRST_PCIEPHY_P>, <&cru SRST_PCIEPHY_PIPE>;
>> +        reset-names = "otg-rst", "combphy-por",
>> +                      "combphy-apb", "combphy-pipe";
>> +        rockchip,combphygrf = <&combphy_grf>;
>> +    };
>> +
>> +...
>> -- 
>> 1.9.1
>>
>>
>>
> 
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
> 
> 
> 

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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-16  0:14       ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-16  0:14 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: shawn.lin, Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Jingoo Han, linux-pci, devicetree,
	William Wu, Simon Xue, linux-rockchip


On 2020/1/16 1:24, Bjorn Helgaas wrote:
> Follow subject line convention.
> 
> On Tue, Jan 14, 2020 at 03:25:01PM +0800, Shawn Lin wrote:
>> From: Simon Xue <xxm@rock-chips.com>
> 
> Needs a commit log.  Please describe the relationship with the
> existing drivers/pci/controller/pcie-rockchip-host.c.  Are they for
> different devices?  Does this supercede the other?

Yes, this PCIe controller is based on dwc IP, however pcie-rockchip* in
drivers/pcie/controller is another IP. They are two different
controllers totally. pcie-rockchip-host is end-of-life due to some
defects, so AFAICT, it's *only* for RK3399 SoC. All the other follow-up
SoCs should use this controller.

> 
>> Signed-off-by: Simon Xue <xxm@rock-chips.com>
>> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
>> ---
>>
>>   drivers/pci/controller/dwc/Kconfig            |   9 +
>>   drivers/pci/controller/dwc/Makefile           |   1 +
>>   drivers/pci/controller/dwc/pcie-dw-rockchip.c | 441 ++++++++++++++++++++++++++
>>   3 files changed, 451 insertions(+)
>>   create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c
>>
>> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
>> index 0830dfc..9160264 100644
>> --- a/drivers/pci/controller/dwc/Kconfig
>> +++ b/drivers/pci/controller/dwc/Kconfig
>> @@ -82,6 +82,15 @@ config PCIE_DW_PLAT_EP
>>   	  order to enable device-specific features PCI_DW_PLAT_EP must be
>>   	  selected.
>>   
>> +config PCIE_DW_ROCKCHIP
>> +	bool "Rockchip DesignWare PCIe controller"
>> +	select PCIE_DW
>> +	select PCIE_DW_HOST
>> +	depends on ARCH_ROCKCHIP
>> +	depends on OF
>> +	help
>> +	  Enables support for the DW PCIe controller in the Rockchip SoC.
> 
> A user needs to be able to tell whether to enable
> CONFIG_PCIE_ROCKCHIP_HOST or CONFIG_PCIE_DW_ROCKCHIP.  Is there an
> endpoint driver coming?  Should this be named PCIE_DW_ROCKCHIP_HOST?

Will add a description to tell users CONFIG_PCIE_ROCKCHIP_HOST is only
for RK3399, so all other Rockchip platforms should use
CONFIG_PCIE_DW_ROCKCHIP.

There is no plan to develop endponit driver recently, but
PCIE_DW_ROCKCHIP_HOST looks sane.


> 
>> +	ret = rockchip_pcie_reset_grant_ctrl(rockchip, true);
>> +	if (ret)
>> +		goto deinit_clk;
>> +
>> +//	if (rockchip->mode == DW_PCIE_RC_TYPE)
>> +//		ret = rk_add_pcie_port(rockchip);
> 
> Remove commented-out code.  I do like an "if" statement better than
> the complicated assignment/ternary thing below, though.
> 

My bad. Will fix it in V2.

>> +	ret = rockchip->mode == DW_PCIE_RC_TYPE ?
>> +		rk_add_pcie_port(rockchip) : -EINVAL;
>> +
>> +	if (ret)
>> +		goto deinit_clk;
> 
> 



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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-16  0:14       ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-16  0:14 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: shawn.lin-TNX95d0MmH7DzftRWevZcw, Heiko Stuebner,
	Lorenzo Pieralisi, Rob Herring, Kishon Vijay Abraham I,
	Jingoo Han, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, William Wu, Simon Xue,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


On 2020/1/16 1:24, Bjorn Helgaas wrote:
> Follow subject line convention.
> 
> On Tue, Jan 14, 2020 at 03:25:01PM +0800, Shawn Lin wrote:
>> From: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> 
> Needs a commit log.  Please describe the relationship with the
> existing drivers/pci/controller/pcie-rockchip-host.c.  Are they for
> different devices?  Does this supercede the other?

Yes, this PCIe controller is based on dwc IP, however pcie-rockchip* in
drivers/pcie/controller is another IP. They are two different
controllers totally. pcie-rockchip-host is end-of-life due to some
defects, so AFAICT, it's *only* for RK3399 SoC. All the other follow-up
SoCs should use this controller.

> 
>> Signed-off-by: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>> Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>> ---
>>
>>   drivers/pci/controller/dwc/Kconfig            |   9 +
>>   drivers/pci/controller/dwc/Makefile           |   1 +
>>   drivers/pci/controller/dwc/pcie-dw-rockchip.c | 441 ++++++++++++++++++++++++++
>>   3 files changed, 451 insertions(+)
>>   create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c
>>
>> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
>> index 0830dfc..9160264 100644
>> --- a/drivers/pci/controller/dwc/Kconfig
>> +++ b/drivers/pci/controller/dwc/Kconfig
>> @@ -82,6 +82,15 @@ config PCIE_DW_PLAT_EP
>>   	  order to enable device-specific features PCI_DW_PLAT_EP must be
>>   	  selected.
>>   
>> +config PCIE_DW_ROCKCHIP
>> +	bool "Rockchip DesignWare PCIe controller"
>> +	select PCIE_DW
>> +	select PCIE_DW_HOST
>> +	depends on ARCH_ROCKCHIP
>> +	depends on OF
>> +	help
>> +	  Enables support for the DW PCIe controller in the Rockchip SoC.
> 
> A user needs to be able to tell whether to enable
> CONFIG_PCIE_ROCKCHIP_HOST or CONFIG_PCIE_DW_ROCKCHIP.  Is there an
> endpoint driver coming?  Should this be named PCIE_DW_ROCKCHIP_HOST?

Will add a description to tell users CONFIG_PCIE_ROCKCHIP_HOST is only
for RK3399, so all other Rockchip platforms should use
CONFIG_PCIE_DW_ROCKCHIP.

There is no plan to develop endponit driver recently, but
PCIE_DW_ROCKCHIP_HOST looks sane.


> 
>> +	ret = rockchip_pcie_reset_grant_ctrl(rockchip, true);
>> +	if (ret)
>> +		goto deinit_clk;
>> +
>> +//	if (rockchip->mode == DW_PCIE_RC_TYPE)
>> +//		ret = rk_add_pcie_port(rockchip);
> 
> Remove commented-out code.  I do like an "if" statement better than
> the complicated assignment/ternary thing below, though.
> 

My bad. Will fix it in V2.

>> +	ret = rockchip->mode == DW_PCIE_RC_TYPE ?
>> +		rk_add_pcie_port(rockchip) : -EINVAL;
>> +
>> +	if (ret)
>> +		goto deinit_clk;
> 
> 

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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-16 21:36     ` Jingoo Han
  0 siblings, 0 replies; 28+ messages in thread
From: Jingoo Han @ 2020-01-16 21:36 UTC (permalink / raw)
  To: Shawn Lin
  Cc: Heiko Stuebner, Lorenzo Pieralisi, Bjorn Helgaas, Rob Herring,
	Kishon Vijay Abraham I, linux-pci, devicetree, William Wu,
	Simon Xue, linux-rockchip, Han Jingoo

On 1/14/20, 2:25 AM, Shawn Lin wrote:
> 
> From: Simon Xue <xxm@rock-chips.com>
>
> Signed-off-by: Simon Xue <xxm@rock-chips.com>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> ---
>
>  drivers/pci/controller/dwc/Kconfig            |   9 +
>  drivers/pci/controller/dwc/Makefile           |   1 +
>  drivers/pci/controller/dwc/pcie-dw-rockchip.c | 441 ++++++++++++++++++++++++++
>  3 files changed, 451 insertions(+)
>  create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c
>
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index 0830dfc..9160264 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -82,6 +82,15 @@ config PCIE_DW_PLAT_EP
>  	  order to enable device-specific features PCI_DW_PLAT_EP must be
>  	  selected.
>  
> +config PCIE_DW_ROCKCHIP
> +	bool "Rockchip DesignWare PCIe controller"
> +	select PCIE_DW
> +	select PCIE_DW_HOST
> +	depends on ARCH_ROCKCHIP
> +	depends on OF
> +	help
> +	  Enables support for the DW PCIe controller in the Rockchip SoC.
> +

The order is PCIE_DW, PCI_*, and PCIE_* as below.

1. Common Frameworks:
    These options are used by other controller drivers.
    e.g., PCIE_DW, PCIE_DW_HOST, PCIE_DW_EP.

2. PCI_* controller drivers:
    PCI_* was used earlier than PCIE_*. If a chip vendor's controllers provide
    both conventional PCI and PCI Express, or only conventional PCI, PCI_* can
    be used.

3. PCIE_* controller drivers
    If a controller can support only PCI Express, not conventional PCI,
    PCIE_* is the proper naming.

Then, within PCI_* or PCIE_* categories, each controller option should be
in an alphabetical order for the readability.

So, add 'PCIE_DW_ROCKCHIP' between 'PCIE_ARTPEC6_EP' and 'PCIE_KIRIN'.

>
>  config PCI_EXYNOS
>  	bool "Samsung Exynos PCIe controller"
>  	depends on SOC_EXYNOS5440 || COMPILE_TEST
> diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
> index 8a637cf..cb4857f 100644
> --- a/drivers/pci/controller/dwc/Makefile
> +++ b/drivers/pci/controller/dwc/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
>  obj-$(CONFIG_PCI_MESON) += pci-meson.o
>  obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
>  obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
> +obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie-dw-rockchip.o

Ditto.

[...]

Best regards,
Jingoo Han


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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-16 21:36     ` Jingoo Han
  0 siblings, 0 replies; 28+ messages in thread
From: Jingoo Han @ 2020-01-16 21:36 UTC (permalink / raw)
  To: Shawn Lin
  Cc: Heiko Stuebner, Lorenzo Pieralisi, Bjorn Helgaas, Rob Herring,
	Kishon Vijay Abraham I, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, William Wu, Simon Xue,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Han Jingoo

On 1/14/20, 2:25 AM, Shawn Lin wrote:
> 
> From: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>
> Signed-off-by: Simon Xue <xxm-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> ---
>
>  drivers/pci/controller/dwc/Kconfig            |   9 +
>  drivers/pci/controller/dwc/Makefile           |   1 +
>  drivers/pci/controller/dwc/pcie-dw-rockchip.c | 441 ++++++++++++++++++++++++++
>  3 files changed, 451 insertions(+)
>  create mode 100644 drivers/pci/controller/dwc/pcie-dw-rockchip.c
>
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index 0830dfc..9160264 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -82,6 +82,15 @@ config PCIE_DW_PLAT_EP
>  	  order to enable device-specific features PCI_DW_PLAT_EP must be
>  	  selected.
>  
> +config PCIE_DW_ROCKCHIP
> +	bool "Rockchip DesignWare PCIe controller"
> +	select PCIE_DW
> +	select PCIE_DW_HOST
> +	depends on ARCH_ROCKCHIP
> +	depends on OF
> +	help
> +	  Enables support for the DW PCIe controller in the Rockchip SoC.
> +

The order is PCIE_DW, PCI_*, and PCIE_* as below.

1. Common Frameworks:
    These options are used by other controller drivers.
    e.g., PCIE_DW, PCIE_DW_HOST, PCIE_DW_EP.

2. PCI_* controller drivers:
    PCI_* was used earlier than PCIE_*. If a chip vendor's controllers provide
    both conventional PCI and PCI Express, or only conventional PCI, PCI_* can
    be used.

3. PCIE_* controller drivers
    If a controller can support only PCI Express, not conventional PCI,
    PCIE_* is the proper naming.

Then, within PCI_* or PCIE_* categories, each controller option should be
in an alphabetical order for the readability.

So, add 'PCIE_DW_ROCKCHIP' between 'PCIE_ARTPEC6_EP' and 'PCIE_KIRIN'.

>
>  config PCI_EXYNOS
>  	bool "Samsung Exynos PCIe controller"
>  	depends on SOC_EXYNOS5440 || COMPILE_TEST
> diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
> index 8a637cf..cb4857f 100644
> --- a/drivers/pci/controller/dwc/Makefile
> +++ b/drivers/pci/controller/dwc/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
>  obj-$(CONFIG_PCI_MESON) += pci-meson.o
>  obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
>  obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
> +obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie-dw-rockchip.o

Ditto.

[...]

Best regards,
Jingoo Han

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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-18 16:36     ` Francesco Lavra
  0 siblings, 0 replies; 28+ messages in thread
From: Francesco Lavra @ 2020-01-18 16:36 UTC (permalink / raw)
  To: Shawn Lin, Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree, Simon Xue, Jingoo Han, linux-rockchip, linux-pci, William Wu

On 1/14/20 8:25 AM, Shawn Lin wrote:
> +static int rockchip_pcie_reset_control_release(struct rockchip_pcie *rockchip)
> +{
> +	struct device *dev = rockchip->pci->dev;
> +	struct property *prop;
> +	const char *name;
> +	int ret, count, i = 0;
> +
> +	count = of_property_count_strings(dev->of_node, "reset-names");
> +	if (count < 1)
> +		return -ENODEV;
> +
> +	rockchip->rsts = devm_kcalloc(dev, count,
> +				     sizeof(struct reset_bulk_data),
> +				     GFP_KERNEL);
> +	if (!rockchip->rsts)
> +		return -ENOMEM;
> +
> +	of_property_for_each_string(dev->of_node, "reset-names",
> +				    prop, name) {
> +		rockchip->rsts[i].id = name;
> +		if (!rockchip->rsts[i].id)
> +			return -ENOMEM;
> +		i++;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		rockchip->rsts[i].rst = devm_reset_control_get_exclusive(dev,
> +						rockchip->rsts[i].id);
> +		if (IS_ERR_OR_NULL(rockchip->rsts[i].rst)) {
> +			dev_err(dev, "failed to get %s\n",
> +				rockchip->clks[i].id);
> +			return -PTR_ERR(rockchip->rsts[i].rst);

IS_ERR_OR_NULL() should be replaced with IS_ERR(), because 
devm_reset_control_get_exclusive() never returns a NULL value.
Also, in case of error you should return the value from PTR_ERR(), 
without the minus sign.

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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-18 16:36     ` Francesco Lavra
  0 siblings, 0 replies; 28+ messages in thread
From: Francesco Lavra @ 2020-01-18 16:36 UTC (permalink / raw)
  To: Shawn Lin, Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu

On 1/14/20 8:25 AM, Shawn Lin wrote:
> +static int rockchip_pcie_reset_control_release(struct rockchip_pcie *rockchip)
> +{
> +	struct device *dev = rockchip->pci->dev;
> +	struct property *prop;
> +	const char *name;
> +	int ret, count, i = 0;
> +
> +	count = of_property_count_strings(dev->of_node, "reset-names");
> +	if (count < 1)
> +		return -ENODEV;
> +
> +	rockchip->rsts = devm_kcalloc(dev, count,
> +				     sizeof(struct reset_bulk_data),
> +				     GFP_KERNEL);
> +	if (!rockchip->rsts)
> +		return -ENOMEM;
> +
> +	of_property_for_each_string(dev->of_node, "reset-names",
> +				    prop, name) {
> +		rockchip->rsts[i].id = name;
> +		if (!rockchip->rsts[i].id)
> +			return -ENOMEM;
> +		i++;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		rockchip->rsts[i].rst = devm_reset_control_get_exclusive(dev,
> +						rockchip->rsts[i].id);
> +		if (IS_ERR_OR_NULL(rockchip->rsts[i].rst)) {
> +			dev_err(dev, "failed to get %s\n",
> +				rockchip->clks[i].id);
> +			return -PTR_ERR(rockchip->rsts[i].rst);

IS_ERR_OR_NULL() should be replaced with IS_ERR(), because 
devm_reset_control_get_exclusive() never returns a NULL value.
Also, in case of error you should return the value from PTR_ERR(), 
without the minus sign.

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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-20  0:55       ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-20  0:55 UTC (permalink / raw)
  To: Francesco Lavra, Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: shawn.lin, devicetree, Simon Xue, Jingoo Han, linux-rockchip,
	linux-pci, William Wu


On 2020/1/19 0:36, Francesco Lavra wrote:
> On 1/14/20 8:25 AM, Shawn Lin wrote:
>> +static int rockchip_pcie_reset_control_release(struct rockchip_pcie 
>> *rockchip)
>> +{
>> +    struct device *dev = rockchip->pci->dev;
>> +    struct property *prop;
>> +    const char *name;
>> +    int ret, count, i = 0;
>> +
>> +    count = of_property_count_strings(dev->of_node, "reset-names");
>> +    if (count < 1)
>> +        return -ENODEV;
>> +
>> +    rockchip->rsts = devm_kcalloc(dev, count,
>> +                     sizeof(struct reset_bulk_data),
>> +                     GFP_KERNEL);
>> +    if (!rockchip->rsts)
>> +        return -ENOMEM;
>> +
>> +    of_property_for_each_string(dev->of_node, "reset-names",
>> +                    prop, name) {
>> +        rockchip->rsts[i].id = name;
>> +        if (!rockchip->rsts[i].id)
>> +            return -ENOMEM;
>> +        i++;
>> +    }
>> +
>> +    for (i = 0; i < count; i++) {
>> +        rockchip->rsts[i].rst = devm_reset_control_get_exclusive(dev,
>> +                        rockchip->rsts[i].id);
>> +        if (IS_ERR_OR_NULL(rockchip->rsts[i].rst)) {
>> +            dev_err(dev, "failed to get %s\n",
>> +                rockchip->clks[i].id);
>> +            return -PTR_ERR(rockchip->rsts[i].rst);
> 
> IS_ERR_OR_NULL() should be replaced with IS_ERR(), because 
> devm_reset_control_get_exclusive() never returns a NULL value.
> Also, in case of error you should return the value from PTR_ERR(), 
> without the minus sign.

Thanks, Francesco. Will fix in v2.

> 
> 



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

* Re: [PATCH 5/6] PCI: rockchip: add DesignWare based PCIe controller
@ 2020-01-20  0:55       ` Shawn Lin
  0 siblings, 0 replies; 28+ messages in thread
From: Shawn Lin @ 2020-01-20  0:55 UTC (permalink / raw)
  To: Francesco Lavra, Heiko Stuebner, Lorenzo Pieralisi, Rob Herring,
	Kishon Vijay Abraham I, Bjorn Helgaas
  Cc: shawn.lin-TNX95d0MmH7DzftRWevZcw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Simon Xue, Jingoo Han,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-pci-u79uwXL29TY76Z2rM5mHXA, William Wu


On 2020/1/19 0:36, Francesco Lavra wrote:
> On 1/14/20 8:25 AM, Shawn Lin wrote:
>> +static int rockchip_pcie_reset_control_release(struct rockchip_pcie 
>> *rockchip)
>> +{
>> +    struct device *dev = rockchip->pci->dev;
>> +    struct property *prop;
>> +    const char *name;
>> +    int ret, count, i = 0;
>> +
>> +    count = of_property_count_strings(dev->of_node, "reset-names");
>> +    if (count < 1)
>> +        return -ENODEV;
>> +
>> +    rockchip->rsts = devm_kcalloc(dev, count,
>> +                     sizeof(struct reset_bulk_data),
>> +                     GFP_KERNEL);
>> +    if (!rockchip->rsts)
>> +        return -ENOMEM;
>> +
>> +    of_property_for_each_string(dev->of_node, "reset-names",
>> +                    prop, name) {
>> +        rockchip->rsts[i].id = name;
>> +        if (!rockchip->rsts[i].id)
>> +            return -ENOMEM;
>> +        i++;
>> +    }
>> +
>> +    for (i = 0; i < count; i++) {
>> +        rockchip->rsts[i].rst = devm_reset_control_get_exclusive(dev,
>> +                        rockchip->rsts[i].id);
>> +        if (IS_ERR_OR_NULL(rockchip->rsts[i].rst)) {
>> +            dev_err(dev, "failed to get %s\n",
>> +                rockchip->clks[i].id);
>> +            return -PTR_ERR(rockchip->rsts[i].rst);
> 
> IS_ERR_OR_NULL() should be replaced with IS_ERR(), because 
> devm_reset_control_get_exclusive() never returns a NULL value.
> Also, in case of error you should return the value from PTR_ERR(), 
> without the minus sign.

Thanks, Francesco. Will fix in v2.

> 
> 

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

end of thread, other threads:[~2020-01-20  0:55 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-14  7:22 [PATCH 0/6] Add Rockchip new PCIe controller and combo phy support Shawn Lin
2020-01-14  7:22 ` Shawn Lin
2020-01-14  7:22 ` [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP Shawn Lin
2020-01-14  7:22   ` Shawn Lin
2020-01-14 23:43   ` Rob Herring
2020-01-14 23:43     ` Rob Herring
2020-01-16  0:03     ` [PATCH 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP【请注意,邮件由linux-rockchip-bounces+shawn.lin=rock-chips.com@lists.infradead.org代发】 Shawn Lin
2020-01-16  0:03       ` Shawn Lin
2020-01-14  7:22 ` [PATCH 2/6] phy/rockchip: inno-combophy: Add initial support Shawn Lin
2020-01-14  7:22   ` Shawn Lin
2020-01-14  7:22 ` [PATCH 3/6] PCI: dwc: Skip allocating own MSI domain if using external MSI domain Shawn Lin
2020-01-14  7:22   ` Shawn Lin
2020-01-14  7:22 ` [PATCH 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller Shawn Lin
2020-01-14  7:22   ` Shawn Lin
2020-01-15  0:05   ` Rob Herring
2020-01-14  7:25 ` [PATCH 5/6] PCI: rockchip: add " Shawn Lin
2020-01-14  7:25   ` Shawn Lin
2020-01-15 17:24   ` Bjorn Helgaas
2020-01-16  0:14     ` Shawn Lin
2020-01-16  0:14       ` Shawn Lin
2020-01-16 21:36   ` Jingoo Han
2020-01-16 21:36     ` Jingoo Han
2020-01-18 16:36   ` Francesco Lavra
2020-01-18 16:36     ` Francesco Lavra
2020-01-20  0:55     ` Shawn Lin
2020-01-20  0:55       ` Shawn Lin
2020-01-14  7:25 ` [PATCH 6/6] MAINTAINERS: Update PCIe drivers for Rockchip Shawn Lin
2020-01-14  7:25   ` Shawn Lin

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.