162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCIe host controller driver for Rockchip SoCs.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
662306a36Sopenharmony_ci *		http://www.rock-chips.com
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Simon Xue <xxm@rock-chips.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1362306a36Sopenharmony_ci#include <linux/irqchip/chained_irq.h>
1462306a36Sopenharmony_ci#include <linux/irqdomain.h>
1562306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/of.h>
1862306a36Sopenharmony_ci#include <linux/of_irq.h>
1962306a36Sopenharmony_ci#include <linux/phy/phy.h>
2062306a36Sopenharmony_ci#include <linux/platform_device.h>
2162306a36Sopenharmony_ci#include <linux/regmap.h>
2262306a36Sopenharmony_ci#include <linux/reset.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "pcie-designware.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * The upper 16 bits of PCIE_CLIENT_CONFIG are a write
2862306a36Sopenharmony_ci * mask for the lower 16 bits.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci#define HIWORD_UPDATE(mask, val) (((mask) << 16) | (val))
3162306a36Sopenharmony_ci#define HIWORD_UPDATE_BIT(val)	HIWORD_UPDATE(val, val)
3262306a36Sopenharmony_ci#define HIWORD_DISABLE_BIT(val)	HIWORD_UPDATE(val, ~val)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define to_rockchip_pcie(x) dev_get_drvdata((x)->dev)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define PCIE_CLIENT_RC_MODE		HIWORD_UPDATE_BIT(0x40)
3762306a36Sopenharmony_ci#define PCIE_CLIENT_ENABLE_LTSSM	HIWORD_UPDATE_BIT(0xc)
3862306a36Sopenharmony_ci#define PCIE_SMLH_LINKUP		BIT(16)
3962306a36Sopenharmony_ci#define PCIE_RDLH_LINKUP		BIT(17)
4062306a36Sopenharmony_ci#define PCIE_LINKUP			(PCIE_SMLH_LINKUP | PCIE_RDLH_LINKUP)
4162306a36Sopenharmony_ci#define PCIE_L0S_ENTRY			0x11
4262306a36Sopenharmony_ci#define PCIE_CLIENT_GENERAL_CONTROL	0x0
4362306a36Sopenharmony_ci#define PCIE_CLIENT_INTR_STATUS_LEGACY	0x8
4462306a36Sopenharmony_ci#define PCIE_CLIENT_INTR_MASK_LEGACY	0x1c
4562306a36Sopenharmony_ci#define PCIE_CLIENT_GENERAL_DEBUG	0x104
4662306a36Sopenharmony_ci#define PCIE_CLIENT_HOT_RESET_CTRL	0x180
4762306a36Sopenharmony_ci#define PCIE_CLIENT_LTSSM_STATUS	0x300
4862306a36Sopenharmony_ci#define PCIE_LTSSM_ENABLE_ENHANCE	BIT(4)
4962306a36Sopenharmony_ci#define PCIE_LTSSM_STATUS_MASK		GENMASK(5, 0)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistruct rockchip_pcie {
5262306a36Sopenharmony_ci	struct dw_pcie			pci;
5362306a36Sopenharmony_ci	void __iomem			*apb_base;
5462306a36Sopenharmony_ci	struct phy			*phy;
5562306a36Sopenharmony_ci	struct clk_bulk_data		*clks;
5662306a36Sopenharmony_ci	unsigned int			clk_cnt;
5762306a36Sopenharmony_ci	struct reset_control		*rst;
5862306a36Sopenharmony_ci	struct gpio_desc		*rst_gpio;
5962306a36Sopenharmony_ci	struct regulator                *vpcie3v3;
6062306a36Sopenharmony_ci	struct irq_domain		*irq_domain;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip,
6462306a36Sopenharmony_ci					     u32 reg)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	return readl_relaxed(rockchip->apb_base + reg);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip,
7062306a36Sopenharmony_ci						u32 val, u32 reg)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	writel_relaxed(val, rockchip->apb_base + reg);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct irq_chip *chip = irq_desc_get_chip(desc);
7862306a36Sopenharmony_ci	struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc);
7962306a36Sopenharmony_ci	unsigned long reg, hwirq;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	chained_irq_enter(chip, desc);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_LEGACY);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	for_each_set_bit(hwirq, &reg, 4)
8662306a36Sopenharmony_ci		generic_handle_domain_irq(rockchip->irq_domain, hwirq);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	chained_irq_exit(chip, desc);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic void rockchip_intx_mask(struct irq_data *data)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data),
9462306a36Sopenharmony_ci				 HIWORD_UPDATE_BIT(BIT(data->hwirq)),
9562306a36Sopenharmony_ci				 PCIE_CLIENT_INTR_MASK_LEGACY);
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic void rockchip_intx_unmask(struct irq_data *data)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	rockchip_pcie_writel_apb(irq_data_get_irq_chip_data(data),
10162306a36Sopenharmony_ci				 HIWORD_DISABLE_BIT(BIT(data->hwirq)),
10262306a36Sopenharmony_ci				 PCIE_CLIENT_INTR_MASK_LEGACY);
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic struct irq_chip rockchip_intx_irq_chip = {
10662306a36Sopenharmony_ci	.name			= "INTx",
10762306a36Sopenharmony_ci	.irq_mask		= rockchip_intx_mask,
10862306a36Sopenharmony_ci	.irq_unmask		= rockchip_intx_unmask,
10962306a36Sopenharmony_ci	.flags			= IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND,
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
11362306a36Sopenharmony_ci				  irq_hw_number_t hwirq)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	irq_set_chip_and_handler(irq, &rockchip_intx_irq_chip, handle_level_irq);
11662306a36Sopenharmony_ci	irq_set_chip_data(irq, domain->host_data);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return 0;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic const struct irq_domain_ops intx_domain_ops = {
12262306a36Sopenharmony_ci	.map = rockchip_pcie_intx_map,
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int rockchip_pcie_init_irq_domain(struct rockchip_pcie *rockchip)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct device *dev = rockchip->pci.dev;
12862306a36Sopenharmony_ci	struct device_node *intc;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	intc = of_get_child_by_name(dev->of_node, "legacy-interrupt-controller");
13162306a36Sopenharmony_ci	if (!intc) {
13262306a36Sopenharmony_ci		dev_err(dev, "missing child interrupt-controller node\n");
13362306a36Sopenharmony_ci		return -EINVAL;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	rockchip->irq_domain = irq_domain_add_linear(intc, PCI_NUM_INTX,
13762306a36Sopenharmony_ci						    &intx_domain_ops, rockchip);
13862306a36Sopenharmony_ci	of_node_put(intc);
13962306a36Sopenharmony_ci	if (!rockchip->irq_domain) {
14062306a36Sopenharmony_ci		dev_err(dev, "failed to get a INTx IRQ domain\n");
14162306a36Sopenharmony_ci		return -EINVAL;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return 0;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void rockchip_pcie_enable_ltssm(struct rockchip_pcie *rockchip)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_ENABLE_LTSSM,
15062306a36Sopenharmony_ci				 PCIE_CLIENT_GENERAL_CONTROL);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic int rockchip_pcie_link_up(struct dw_pcie *pci)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
15662306a36Sopenharmony_ci	u32 val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if ((val & PCIE_LINKUP) == PCIE_LINKUP &&
15962306a36Sopenharmony_ci	    (val & PCIE_LTSSM_STATUS_MASK) == PCIE_L0S_ENTRY)
16062306a36Sopenharmony_ci		return 1;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int rockchip_pcie_start_link(struct dw_pcie *pci)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* Reset device */
17062306a36Sopenharmony_ci	gpiod_set_value_cansleep(rockchip->rst_gpio, 0);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	rockchip_pcie_enable_ltssm(rockchip);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/*
17562306a36Sopenharmony_ci	 * PCIe requires the refclk to be stable for 100µs prior to releasing
17662306a36Sopenharmony_ci	 * PERST. See table 2-4 in section 2.6.2 AC Specifications of the PCI
17762306a36Sopenharmony_ci	 * Express Card Electromechanical Specification, 1.1. However, we don't
17862306a36Sopenharmony_ci	 * know if the refclk is coming from RC's PHY or external OSC. If it's
17962306a36Sopenharmony_ci	 * from RC, so enabling LTSSM is the just right place to release #PERST.
18062306a36Sopenharmony_ci	 * We need more extra time as before, rather than setting just
18162306a36Sopenharmony_ci	 * 100us as we don't know how long should the device need to reset.
18262306a36Sopenharmony_ci	 */
18362306a36Sopenharmony_ci	msleep(100);
18462306a36Sopenharmony_ci	gpiod_set_value_cansleep(rockchip->rst_gpio, 1);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
19262306a36Sopenharmony_ci	struct rockchip_pcie *rockchip = to_rockchip_pcie(pci);
19362306a36Sopenharmony_ci	struct device *dev = rockchip->pci.dev;
19462306a36Sopenharmony_ci	u32 val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE);
19562306a36Sopenharmony_ci	int irq, ret;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	irq = of_irq_get_byname(dev->of_node, "legacy");
19862306a36Sopenharmony_ci	if (irq < 0)
19962306a36Sopenharmony_ci		return irq;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	ret = rockchip_pcie_init_irq_domain(rockchip);
20262306a36Sopenharmony_ci	if (ret < 0)
20362306a36Sopenharmony_ci		dev_err(dev, "failed to init irq domain\n");
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	irq_set_chained_handler_and_data(irq, rockchip_pcie_legacy_int_handler,
20662306a36Sopenharmony_ci					 rockchip);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* LTSSM enable control mode */
20962306a36Sopenharmony_ci	rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_RC_MODE,
21262306a36Sopenharmony_ci				 PCIE_CLIENT_GENERAL_CONTROL);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return 0;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
21862306a36Sopenharmony_ci	.host_init = rockchip_pcie_host_init,
21962306a36Sopenharmony_ci};
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int rockchip_pcie_clk_init(struct rockchip_pcie *rockchip)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct device *dev = rockchip->pci.dev;
22462306a36Sopenharmony_ci	int ret;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	ret = devm_clk_bulk_get_all(dev, &rockchip->clks);
22762306a36Sopenharmony_ci	if (ret < 0)
22862306a36Sopenharmony_ci		return ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	rockchip->clk_cnt = ret;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return clk_bulk_prepare_enable(rockchip->clk_cnt, rockchip->clks);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic int rockchip_pcie_resource_get(struct platform_device *pdev,
23662306a36Sopenharmony_ci				      struct rockchip_pcie *rockchip)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	rockchip->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb");
23962306a36Sopenharmony_ci	if (IS_ERR(rockchip->apb_base))
24062306a36Sopenharmony_ci		return PTR_ERR(rockchip->apb_base);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	rockchip->rst_gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
24362306a36Sopenharmony_ci						     GPIOD_OUT_HIGH);
24462306a36Sopenharmony_ci	if (IS_ERR(rockchip->rst_gpio))
24562306a36Sopenharmony_ci		return PTR_ERR(rockchip->rst_gpio);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	rockchip->rst = devm_reset_control_array_get_exclusive(&pdev->dev);
24862306a36Sopenharmony_ci	if (IS_ERR(rockchip->rst))
24962306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(rockchip->rst),
25062306a36Sopenharmony_ci				     "failed to get reset lines\n");
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return 0;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic int rockchip_pcie_phy_init(struct rockchip_pcie *rockchip)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct device *dev = rockchip->pci.dev;
25862306a36Sopenharmony_ci	int ret;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	rockchip->phy = devm_phy_get(dev, "pcie-phy");
26162306a36Sopenharmony_ci	if (IS_ERR(rockchip->phy))
26262306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(rockchip->phy),
26362306a36Sopenharmony_ci				     "missing PHY\n");
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	ret = phy_init(rockchip->phy);
26662306a36Sopenharmony_ci	if (ret < 0)
26762306a36Sopenharmony_ci		return ret;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	ret = phy_power_on(rockchip->phy);
27062306a36Sopenharmony_ci	if (ret)
27162306a36Sopenharmony_ci		phy_exit(rockchip->phy);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return ret;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic void rockchip_pcie_phy_deinit(struct rockchip_pcie *rockchip)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	phy_exit(rockchip->phy);
27962306a36Sopenharmony_ci	phy_power_off(rockchip->phy);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic const struct dw_pcie_ops dw_pcie_ops = {
28362306a36Sopenharmony_ci	.link_up = rockchip_pcie_link_up,
28462306a36Sopenharmony_ci	.start_link = rockchip_pcie_start_link,
28562306a36Sopenharmony_ci};
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic int rockchip_pcie_probe(struct platform_device *pdev)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
29062306a36Sopenharmony_ci	struct rockchip_pcie *rockchip;
29162306a36Sopenharmony_ci	struct dw_pcie_rp *pp;
29262306a36Sopenharmony_ci	int ret;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
29562306a36Sopenharmony_ci	if (!rockchip)
29662306a36Sopenharmony_ci		return -ENOMEM;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	platform_set_drvdata(pdev, rockchip);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	rockchip->pci.dev = dev;
30162306a36Sopenharmony_ci	rockchip->pci.ops = &dw_pcie_ops;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	pp = &rockchip->pci.pp;
30462306a36Sopenharmony_ci	pp->ops = &rockchip_pcie_host_ops;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	ret = rockchip_pcie_resource_get(pdev, rockchip);
30762306a36Sopenharmony_ci	if (ret)
30862306a36Sopenharmony_ci		return ret;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ret = reset_control_assert(rockchip->rst);
31162306a36Sopenharmony_ci	if (ret)
31262306a36Sopenharmony_ci		return ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* DON'T MOVE ME: must be enable before PHY init */
31562306a36Sopenharmony_ci	rockchip->vpcie3v3 = devm_regulator_get_optional(dev, "vpcie3v3");
31662306a36Sopenharmony_ci	if (IS_ERR(rockchip->vpcie3v3)) {
31762306a36Sopenharmony_ci		if (PTR_ERR(rockchip->vpcie3v3) != -ENODEV)
31862306a36Sopenharmony_ci			return dev_err_probe(dev, PTR_ERR(rockchip->vpcie3v3),
31962306a36Sopenharmony_ci					"failed to get vpcie3v3 regulator\n");
32062306a36Sopenharmony_ci		rockchip->vpcie3v3 = NULL;
32162306a36Sopenharmony_ci	} else {
32262306a36Sopenharmony_ci		ret = regulator_enable(rockchip->vpcie3v3);
32362306a36Sopenharmony_ci		if (ret) {
32462306a36Sopenharmony_ci			dev_err(dev, "failed to enable vpcie3v3 regulator\n");
32562306a36Sopenharmony_ci			return ret;
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = rockchip_pcie_phy_init(rockchip);
33062306a36Sopenharmony_ci	if (ret)
33162306a36Sopenharmony_ci		goto disable_regulator;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ret = reset_control_deassert(rockchip->rst);
33462306a36Sopenharmony_ci	if (ret)
33562306a36Sopenharmony_ci		goto deinit_phy;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	ret = rockchip_pcie_clk_init(rockchip);
33862306a36Sopenharmony_ci	if (ret)
33962306a36Sopenharmony_ci		goto deinit_phy;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	ret = dw_pcie_host_init(pp);
34262306a36Sopenharmony_ci	if (!ret)
34362306a36Sopenharmony_ci		return 0;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	clk_bulk_disable_unprepare(rockchip->clk_cnt, rockchip->clks);
34662306a36Sopenharmony_cideinit_phy:
34762306a36Sopenharmony_ci	rockchip_pcie_phy_deinit(rockchip);
34862306a36Sopenharmony_cidisable_regulator:
34962306a36Sopenharmony_ci	if (rockchip->vpcie3v3)
35062306a36Sopenharmony_ci		regulator_disable(rockchip->vpcie3v3);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	return ret;
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic const struct of_device_id rockchip_pcie_of_match[] = {
35662306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3568-pcie", },
35762306a36Sopenharmony_ci	{},
35862306a36Sopenharmony_ci};
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic struct platform_driver rockchip_pcie_driver = {
36162306a36Sopenharmony_ci	.driver = {
36262306a36Sopenharmony_ci		.name	= "rockchip-dw-pcie",
36362306a36Sopenharmony_ci		.of_match_table = rockchip_pcie_of_match,
36462306a36Sopenharmony_ci		.suppress_bind_attrs = true,
36562306a36Sopenharmony_ci	},
36662306a36Sopenharmony_ci	.probe = rockchip_pcie_probe,
36762306a36Sopenharmony_ci};
36862306a36Sopenharmony_cibuiltin_platform_driver(rockchip_pcie_driver);
369