Linux-PCI Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v2 0/6] Add Rockchip new PCIe controller and combo phy support
@ 2020-02-13  6:08 Shawn Lin
  2020-02-13  6:08 ` [PATCH v2 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP Shawn Lin
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Shawn Lin @ 2020-02-13  6:08 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.


Changes in v2:
- fix yaml format
- add commit log and fix Kconfig
- remove dead code

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  |  148 +++
 .../bindings/phy/rockchip,inno-combophy.yaml       |   80 ++
 MAINTAINERS                                        |    4 +-
 drivers/pci/controller/Kconfig                     |    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      |  439 ++++++++
 drivers/phy/rockchip/Kconfig                       |    8 +
 drivers/phy/rockchip/Makefile                      |    1 +
 drivers/phy/rockchip/phy-rockchip-inno-combphy.c   | 1056 ++++++++++++++++++++
 12 files changed, 1757 insertions(+), 4 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] 10+ messages in thread

* [PATCH v2 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP
  2020-02-13  6:08 [PATCH v2 0/6] Add Rockchip new PCIe controller and combo phy support Shawn Lin
@ 2020-02-13  6:08 ` Shawn Lin
  2020-02-13 20:46   ` Rob Herring
  2020-02-14  9:20   ` Heiko Stuebner
  2020-02-13  6:08 ` [PATCH v2 2/6] phy/rockchip: inno-combophy: Add initial support Shawn Lin
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 10+ messages in thread
From: Shawn Lin @ 2020-02-13  6:08 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>

---

Changes in v2:
- fix yaml format

 .../bindings/phy/rockchip,inno-combophy.yaml       | 80 ++++++++++++++++++++++
 1 file changed, 80 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..841f88a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
@@ -0,0 +1,80 @@
+# 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:
+    enum:
+      - rockchip,combphygrf
+    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: 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] 10+ messages in thread

* [PATCH v2 2/6] phy/rockchip: inno-combophy: Add initial support
  2020-02-13  6:08 [PATCH v2 0/6] Add Rockchip new PCIe controller and combo phy support Shawn Lin
  2020-02-13  6:08 ` [PATCH v2 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP Shawn Lin
@ 2020-02-13  6:08 ` Shawn Lin
  2020-02-13  6:08 ` [PATCH v2 3/6] PCI: dwc: Skip allocating own MSI domain if using external MSI domain Shawn Lin
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Shawn Lin @ 2020-02-13  6:08 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>
---

Changes in v2: None

 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	[flat|nested] 10+ messages in thread

* [PATCH v2 3/6] PCI: dwc: Skip allocating own MSI domain if using external MSI domain
  2020-02-13  6:08 [PATCH v2 0/6] Add Rockchip new PCIe controller and combo phy support Shawn Lin
  2020-02-13  6:08 ` [PATCH v2 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP Shawn Lin
  2020-02-13  6:08 ` [PATCH v2 2/6] phy/rockchip: inno-combophy: Add initial support Shawn Lin
@ 2020-02-13  6:08 ` Shawn Lin
  2020-02-13  6:08 ` [PATCH v2 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller Shawn Lin
  2020-02-13  6:10 ` [PATCH v2 5/6] PCI: rockchip: add " Shawn Lin
  4 siblings, 0 replies; 10+ messages in thread
From: Shawn Lin @ 2020-02-13  6:08 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>
---

Changes in v2: None

 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	[flat|nested] 10+ messages in thread

* [PATCH v2 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller
  2020-02-13  6:08 [PATCH v2 0/6] Add Rockchip new PCIe controller and combo phy support Shawn Lin
                   ` (2 preceding siblings ...)
  2020-02-13  6:08 ` [PATCH v2 3/6] PCI: dwc: Skip allocating own MSI domain if using external MSI domain Shawn Lin
@ 2020-02-13  6:08 ` Shawn Lin
  2020-02-13 20:47   ` Rob Herring
  2020-02-13  6:10 ` [PATCH v2 5/6] PCI: rockchip: add " Shawn Lin
  4 siblings, 1 reply; 10+ messages in thread
From: Shawn Lin @ 2020-02-13  6:08 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>

---

Changes in v2:
- fix yaml format

 .../devicetree/bindings/pci/rockchip-dw-pcie.yaml  | 148 +++++++++++++++++++++
 1 file changed, 148 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..527c770
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
@@ -0,0 +1,148 @@
+# 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>
+
+# We need a select here so we don't match all nodes with 'snps,dw-pcie'
+select:
+  properties:
+    compatible:
+      contains:
+        const: rockchip,rk1808-pcie
+  required:
+    - compatible
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk1808-pcie
+      - snps,dw-pcie
+
+  reg:
+    maxItems: 1
+
+  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:
+    enum:
+      - rockchip,usbpciegrf
+    description: The grf for COMBPHY configuration and state registers.
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+  - reg
+  - clocks
+  - clock-names
+  - msi-map
+  - num-lanes
+  - phys
+  - phy-names
+  - ranges
+  - resets
+  - reset-names
+  - rockchip,usbpciegrf
+  - reset-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    pcie0: pcie@fc400000 {
+      compatible = "rockchip,rk1808-pcie", "snps,dw-pcie";
+      #address-cells = <3>;
+      #size-cells = <2>;
+      bus-range = <0x0 0x1f>;
+      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";
+      ranges = <0x00000800 0x0 0xf8000000 0x0 0xf8000000 0x0 0x800000
+                0x83000000 0x0 0xf8800000 0x0 0xf8800000 0x0 0x3700000
+                0x81000000 0x0 0xfbf00000 0x0 0xfbf00000 0x0 0x100000>;
+      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>;
+      reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>;
+    };
+
+...
-- 
1.9.1




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

* [PATCH v2 5/6] PCI: rockchip: add DesignWare based PCIe controller
  2020-02-13  6:08 [PATCH v2 0/6] Add Rockchip new PCIe controller and combo phy support Shawn Lin
                   ` (3 preceding siblings ...)
  2020-02-13  6:08 ` [PATCH v2 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller Shawn Lin
@ 2020-02-13  6:10 ` " Shawn Lin
  2020-02-13  6:10   ` [PATCH v2 6/6] MAINTAINERS: Update PCIe drivers for Rockchip Shawn Lin
  4 siblings, 1 reply; 10+ messages in thread
From: Shawn Lin @ 2020-02-13  6:10 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>

pcie-dw-rockchip is based on DWC IP. But pcie-rockchip-host
is another IP which is only used for RK3399. So all the following
non-RK3399 SoCs should use this driver.

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

---

Changes in v2:
- add commit log
- remove dead code

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

diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 20bf00f..d0bc8c5 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -190,7 +190,7 @@ config PCIE_ROCKCHIP_HOST
 	help
 	  Say Y here if you want internal PCI support on Rockchip SoC.
 	  There is 1 internal PCIe port available to support GEN2 with
-	  4 slots.
+	  4 slots. Only for RK3399.
 
 config PCIE_ROCKCHIP_EP
 	bool "Rockchip PCIe endpoint controller"
@@ -202,7 +202,7 @@ config PCIE_ROCKCHIP_EP
 	help
 	  Say Y here if you want to support Rockchip PCIe controller in
 	  endpoint mode on Rockchip SoC. There is 1 internal PCIe port
-	  available to support GEN2 with 4 slots.
+	  available to support GEN2 with 4 slots. Only for RK3399.
 
 config PCIE_MEDIATEK
 	tristate "MediaTek PCIe controller"
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 0830dfc..9e42a2b 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -209,6 +209,15 @@ config PCIE_ARTPEC6_EP
 	  Enables support for the PCIe controller in the ARTPEC-6 SoC to work in
 	  endpoint mode. This uses the DesignWare core.
 
+config PCIE_DW_ROCKCHIP_HOST
+	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 PCIE_INTEL_GW
 	bool "Intel Gateway PCIe host controller support"
 	depends on OF && (X86 || COMPILE_TEST)
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 8a637cf..1793e81 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o
 obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
 obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
+obj-$(CONFIG_PCIE_DW_ROCKCHIP_HOST) += pcie-dw-rockchip.o
 obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
 obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
 obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
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..df413aa
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -0,0 +1,439 @@
+// 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 rockchip_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(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 = rockchip_add_pcie_port(rockchip);
+
+	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	[flat|nested] 10+ messages in thread

* [PATCH v2 6/6] MAINTAINERS: Update PCIe drivers for Rockchip
  2020-02-13  6:10 ` [PATCH v2 5/6] PCI: rockchip: add " Shawn Lin
@ 2020-02-13  6:10   ` Shawn Lin
  0 siblings, 0 replies; 10+ messages in thread
From: Shawn Lin @ 2020-02-13  6:10 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>
---

Changes in v2: None

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

diff --git a/MAINTAINERS b/MAINTAINERS
index ad462f6..31682ae 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13025,11 +13025,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	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP
  2020-02-13  6:08 ` [PATCH v2 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP Shawn Lin
@ 2020-02-13 20:46   ` Rob Herring
  2020-02-14  9:20   ` Heiko Stuebner
  1 sibling, 0 replies; 10+ messages in thread
From: Rob Herring @ 2020-02-13 20:46 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, Shawn Lin

On Thu, 13 Feb 2020 14:08:06 +0800, Shawn Lin wrote:
> This IP could supports USB3.0 and PCIe.
> 
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> 
> ---
> 
> Changes in v2:
> - fix yaml format
> 
>  .../bindings/phy/rockchip,inno-combophy.yaml       | 80 ++++++++++++++++++++++
>  1 file changed, 80 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/rockchip,inno-combophy.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

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
Error: Documentation/devicetree/bindings/phy/rockchip,inno-combophy.example.dts:21.28-29 syntax error
FATAL ERROR: Unable to parse input tree
scripts/Makefile.lib:300: recipe for target 'Documentation/devicetree/bindings/phy/rockchip,inno-combophy.example.dt.yaml' failed
make[1]: *** [Documentation/devicetree/bindings/phy/rockchip,inno-combophy.example.dt.yaml] Error 1
Makefile:1263: recipe for target 'dt_binding_check' failed
make: *** [dt_binding_check] Error 2

See https://patchwork.ozlabs.org/patch/1237296
Please check and re-submit.

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

* Re: [PATCH v2 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller
  2020-02-13  6:08 ` [PATCH v2 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller Shawn Lin
@ 2020-02-13 20:47   ` Rob Herring
  0 siblings, 0 replies; 10+ messages in thread
From: Rob Herring @ 2020-02-13 20:47 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, Shawn Lin

On Thu, 13 Feb 2020 14:08:09 +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>
> 
> ---
> 
> Changes in v2:
> - fix yaml format
> 
>  .../devicetree/bindings/pci/rockchip-dw-pcie.yaml  | 148 +++++++++++++++++++++
>  1 file changed, 148 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

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
Error: Documentation/devicetree/bindings/pci/rockchip-dw-pcie.example.dts:24.26-27 syntax error
FATAL ERROR: Unable to parse input tree
scripts/Makefile.lib:300: recipe for target 'Documentation/devicetree/bindings/pci/rockchip-dw-pcie.example.dt.yaml' failed
make[1]: *** [Documentation/devicetree/bindings/pci/rockchip-dw-pcie.example.dt.yaml] Error 1
Makefile:1263: recipe for target 'dt_binding_check' failed
make: *** [dt_binding_check] Error 2

See https://patchwork.ozlabs.org/patch/1237300
Please check and re-submit.

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

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

Hi Shawn,

Am Donnerstag, 13. Februar 2020, 07:08:06 CET schrieb Shawn Lin:
> This IP could supports USB3.0 and PCIe.
> 
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> 
> ---
> 
> Changes in v2:
> - fix yaml format
> 
>  .../bindings/phy/rockchip,inno-combophy.yaml       | 80 ++++++++++++++++++++++

can we make this rockchip,inno-usb3pciephy or something similar please?
Same for the driver name.

-combophy is completely non-descriptive and looking at the Rockchip
vendor-tree we already have:

- phy-rockchip-inno-combphy.c (this one)
- phy-rockchip-inno-mipi-dphy.c (rk1808 dsi, but should actually fit into combo)
- phy-rockchip-inno-video-combo-phy.c (dsi/lvds/ttl)
- phy-rockchip-inno-video-phy.c (rk3288-lvds)

All of them have quite none-descriptive names

The inno-video-combo-phy already got a somewhat nicer name in
mainline (dsidphy), so I think it would be cool to also do this here
(and for the driver of course).


> +  reset-names:
> +    items:
> +      - const: otg-rst
> +      - const: combphy-por
> +      - const: combphy-apb
> +      - const: combphy-pipe

reset-names are local to the node, so there is no need
for combophy prefixes, so these should probably be:

      - const: otg-rst
      - const: por
      - const: apb
      - const: pipe


> +
> +  rockchip,combphygrf:
> +    enum:
> +      - rockchip,combphygrf

nicer name here? :-)


Thanks
Heiko



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

end of thread, back to index

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-13  6:08 [PATCH v2 0/6] Add Rockchip new PCIe controller and combo phy support Shawn Lin
2020-02-13  6:08 ` [PATCH v2 1/6] dt-bindings: add binding for Rockchip combo phy using an Innosilicon IP Shawn Lin
2020-02-13 20:46   ` Rob Herring
2020-02-14  9:20   ` Heiko Stuebner
2020-02-13  6:08 ` [PATCH v2 2/6] phy/rockchip: inno-combophy: Add initial support Shawn Lin
2020-02-13  6:08 ` [PATCH v2 3/6] PCI: dwc: Skip allocating own MSI domain if using external MSI domain Shawn Lin
2020-02-13  6:08 ` [PATCH v2 4/6] dt-bindings: rockchip: Add DesignWare based PCIe controller Shawn Lin
2020-02-13 20:47   ` Rob Herring
2020-02-13  6:10 ` [PATCH v2 5/6] PCI: rockchip: add " Shawn Lin
2020-02-13  6:10   ` [PATCH v2 6/6] MAINTAINERS: Update PCIe drivers for Rockchip Shawn Lin

Linux-PCI Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-pci/0 linux-pci/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-pci linux-pci/ https://lore.kernel.org/linux-pci \
		linux-pci@vger.kernel.org
	public-inbox-index linux-pci

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-pci


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git