18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCIe host controller driver for UniPhier SoCs
48c2ecf20Sopenharmony_ci * Copyright 2018 Socionext Inc.
58c2ecf20Sopenharmony_ci * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bitops.h>
98c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
158c2ecf20Sopenharmony_ci#include <linux/irqchip/chained_irq.h>
168c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
178c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
188c2ecf20Sopenharmony_ci#include <linux/pci.h>
198c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
218c2ecf20Sopenharmony_ci#include <linux/reset.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "pcie-designware.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define PCL_PINCTRL0			0x002c
268c2ecf20Sopenharmony_ci#define PCL_PERST_PLDN_REGEN		BIT(12)
278c2ecf20Sopenharmony_ci#define PCL_PERST_NOE_REGEN		BIT(11)
288c2ecf20Sopenharmony_ci#define PCL_PERST_OUT_REGEN		BIT(8)
298c2ecf20Sopenharmony_ci#define PCL_PERST_PLDN_REGVAL		BIT(4)
308c2ecf20Sopenharmony_ci#define PCL_PERST_NOE_REGVAL		BIT(3)
318c2ecf20Sopenharmony_ci#define PCL_PERST_OUT_REGVAL		BIT(0)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define PCL_PIPEMON			0x0044
348c2ecf20Sopenharmony_ci#define PCL_PCLK_ALIVE			BIT(15)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define PCL_MODE			0x8000
378c2ecf20Sopenharmony_ci#define PCL_MODE_REGEN			BIT(8)
388c2ecf20Sopenharmony_ci#define PCL_MODE_REGVAL			BIT(0)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define PCL_APP_READY_CTRL		0x8008
418c2ecf20Sopenharmony_ci#define PCL_APP_LTSSM_ENABLE		BIT(0)
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define PCL_APP_PM0			0x8078
448c2ecf20Sopenharmony_ci#define PCL_SYS_AUX_PWR_DET		BIT(8)
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define PCL_RCV_INT			0x8108
478c2ecf20Sopenharmony_ci#define PCL_RCV_INT_ALL_ENABLE		GENMASK(20, 17)
488c2ecf20Sopenharmony_ci#define PCL_CFG_BW_MGT_STATUS		BIT(4)
498c2ecf20Sopenharmony_ci#define PCL_CFG_LINK_AUTO_BW_STATUS	BIT(3)
508c2ecf20Sopenharmony_ci#define PCL_CFG_AER_RC_ERR_MSI_STATUS	BIT(2)
518c2ecf20Sopenharmony_ci#define PCL_CFG_PME_MSI_STATUS		BIT(1)
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define PCL_RCV_INTX			0x810c
548c2ecf20Sopenharmony_ci#define PCL_RCV_INTX_ALL_ENABLE		GENMASK(19, 16)
558c2ecf20Sopenharmony_ci#define PCL_RCV_INTX_ALL_MASK		GENMASK(11, 8)
568c2ecf20Sopenharmony_ci#define PCL_RCV_INTX_MASK_SHIFT		8
578c2ecf20Sopenharmony_ci#define PCL_RCV_INTX_ALL_STATUS		GENMASK(3, 0)
588c2ecf20Sopenharmony_ci#define PCL_RCV_INTX_STATUS_SHIFT	0
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define PCL_STATUS_LINK			0x8140
618c2ecf20Sopenharmony_ci#define PCL_RDLH_LINK_UP		BIT(1)
628c2ecf20Sopenharmony_ci#define PCL_XMLH_LINK_UP		BIT(0)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistruct uniphier_pcie_priv {
658c2ecf20Sopenharmony_ci	void __iomem *base;
668c2ecf20Sopenharmony_ci	struct dw_pcie pci;
678c2ecf20Sopenharmony_ci	struct clk *clk;
688c2ecf20Sopenharmony_ci	struct reset_control *rst;
698c2ecf20Sopenharmony_ci	struct phy *phy;
708c2ecf20Sopenharmony_ci	struct irq_domain *legacy_irq_domain;
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define to_uniphier_pcie(x)	dev_get_drvdata((x)->dev)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void uniphier_pcie_ltssm_enable(struct uniphier_pcie_priv *priv,
768c2ecf20Sopenharmony_ci				       bool enable)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	u32 val;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_APP_READY_CTRL);
818c2ecf20Sopenharmony_ci	if (enable)
828c2ecf20Sopenharmony_ci		val |= PCL_APP_LTSSM_ENABLE;
838c2ecf20Sopenharmony_ci	else
848c2ecf20Sopenharmony_ci		val &= ~PCL_APP_LTSSM_ENABLE;
858c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_APP_READY_CTRL);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic void uniphier_pcie_init_rc(struct uniphier_pcie_priv *priv)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	u32 val;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* set RC MODE */
938c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_MODE);
948c2ecf20Sopenharmony_ci	val |= PCL_MODE_REGEN;
958c2ecf20Sopenharmony_ci	val &= ~PCL_MODE_REGVAL;
968c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_MODE);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* use auxiliary power detection */
998c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_APP_PM0);
1008c2ecf20Sopenharmony_ci	val |= PCL_SYS_AUX_PWR_DET;
1018c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_APP_PM0);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/* assert PERST# */
1048c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_PINCTRL0);
1058c2ecf20Sopenharmony_ci	val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL
1068c2ecf20Sopenharmony_ci		 | PCL_PERST_PLDN_REGVAL);
1078c2ecf20Sopenharmony_ci	val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN
1088c2ecf20Sopenharmony_ci		| PCL_PERST_PLDN_REGEN;
1098c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_PINCTRL0);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	uniphier_pcie_ltssm_enable(priv, false);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	usleep_range(100000, 200000);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* deassert PERST# */
1168c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_PINCTRL0);
1178c2ecf20Sopenharmony_ci	val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;
1188c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_PINCTRL0);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic int uniphier_pcie_wait_rc(struct uniphier_pcie_priv *priv)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	u32 status;
1248c2ecf20Sopenharmony_ci	int ret;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* wait PIPE clock */
1278c2ecf20Sopenharmony_ci	ret = readl_poll_timeout(priv->base + PCL_PIPEMON, status,
1288c2ecf20Sopenharmony_ci				 status & PCL_PCLK_ALIVE, 100000, 1000000);
1298c2ecf20Sopenharmony_ci	if (ret) {
1308c2ecf20Sopenharmony_ci		dev_err(priv->pci.dev,
1318c2ecf20Sopenharmony_ci			"Failed to initialize controller in RC mode\n");
1328c2ecf20Sopenharmony_ci		return ret;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return 0;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int uniphier_pcie_link_up(struct dw_pcie *pci)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
1418c2ecf20Sopenharmony_ci	u32 val, mask;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_STATUS_LINK);
1448c2ecf20Sopenharmony_ci	mask = PCL_RDLH_LINK_UP | PCL_XMLH_LINK_UP;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	return (val & mask) == mask;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int uniphier_pcie_establish_link(struct dw_pcie *pci)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (dw_pcie_link_up(pci))
1548c2ecf20Sopenharmony_ci		return 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	uniphier_pcie_ltssm_enable(priv, true);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	return dw_pcie_wait_for_link(pci);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic void uniphier_pcie_stop_link(struct dw_pcie *pci)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	uniphier_pcie_ltssm_enable(priv, false);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic void uniphier_pcie_irq_enable(struct uniphier_pcie_priv *priv)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	writel(PCL_RCV_INT_ALL_ENABLE, priv->base + PCL_RCV_INT);
1718c2ecf20Sopenharmony_ci	writel(PCL_RCV_INTX_ALL_ENABLE, priv->base + PCL_RCV_INTX);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic void uniphier_pcie_irq_mask(struct irq_data *d)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct pcie_port *pp = irq_data_get_irq_chip_data(d);
1778c2ecf20Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
1788c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
1798c2ecf20Sopenharmony_ci	unsigned long flags;
1808c2ecf20Sopenharmony_ci	u32 val;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pp->lock, flags);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_RCV_INTX);
1858c2ecf20Sopenharmony_ci	val |= BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);
1868c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_RCV_INTX);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pp->lock, flags);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic void uniphier_pcie_irq_unmask(struct irq_data *d)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct pcie_port *pp = irq_data_get_irq_chip_data(d);
1948c2ecf20Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
1958c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
1968c2ecf20Sopenharmony_ci	unsigned long flags;
1978c2ecf20Sopenharmony_ci	u32 val;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pp->lock, flags);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_RCV_INTX);
2028c2ecf20Sopenharmony_ci	val &= ~BIT(irqd_to_hwirq(d) + PCL_RCV_INTX_MASK_SHIFT);
2038c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_RCV_INTX);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pp->lock, flags);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic struct irq_chip uniphier_pcie_irq_chip = {
2098c2ecf20Sopenharmony_ci	.name = "PCI",
2108c2ecf20Sopenharmony_ci	.irq_mask = uniphier_pcie_irq_mask,
2118c2ecf20Sopenharmony_ci	.irq_unmask = uniphier_pcie_irq_unmask,
2128c2ecf20Sopenharmony_ci};
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int uniphier_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
2158c2ecf20Sopenharmony_ci				  irq_hw_number_t hwirq)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	irq_set_chip_and_handler(irq, &uniphier_pcie_irq_chip,
2188c2ecf20Sopenharmony_ci				 handle_level_irq);
2198c2ecf20Sopenharmony_ci	irq_set_chip_data(irq, domain->host_data);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic const struct irq_domain_ops uniphier_intx_domain_ops = {
2258c2ecf20Sopenharmony_ci	.map = uniphier_pcie_intx_map,
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic void uniphier_pcie_irq_handler(struct irq_desc *desc)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct pcie_port *pp = irq_desc_get_handler_data(desc);
2318c2ecf20Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
2328c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
2338c2ecf20Sopenharmony_ci	struct irq_chip *chip = irq_desc_get_chip(desc);
2348c2ecf20Sopenharmony_ci	unsigned long reg;
2358c2ecf20Sopenharmony_ci	u32 val, bit, virq;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* INT for debug */
2388c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_RCV_INT);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (val & PCL_CFG_BW_MGT_STATUS)
2418c2ecf20Sopenharmony_ci		dev_dbg(pci->dev, "Link Bandwidth Management Event\n");
2428c2ecf20Sopenharmony_ci	if (val & PCL_CFG_LINK_AUTO_BW_STATUS)
2438c2ecf20Sopenharmony_ci		dev_dbg(pci->dev, "Link Autonomous Bandwidth Event\n");
2448c2ecf20Sopenharmony_ci	if (val & PCL_CFG_AER_RC_ERR_MSI_STATUS)
2458c2ecf20Sopenharmony_ci		dev_dbg(pci->dev, "Root Error\n");
2468c2ecf20Sopenharmony_ci	if (val & PCL_CFG_PME_MSI_STATUS)
2478c2ecf20Sopenharmony_ci		dev_dbg(pci->dev, "PME Interrupt\n");
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	writel(val, priv->base + PCL_RCV_INT);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* INTx */
2528c2ecf20Sopenharmony_ci	chained_irq_enter(chip, desc);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	val = readl(priv->base + PCL_RCV_INTX);
2558c2ecf20Sopenharmony_ci	reg = FIELD_GET(PCL_RCV_INTX_ALL_STATUS, val);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	for_each_set_bit(bit, &reg, PCI_NUM_INTX) {
2588c2ecf20Sopenharmony_ci		virq = irq_linear_revmap(priv->legacy_irq_domain, bit);
2598c2ecf20Sopenharmony_ci		generic_handle_irq(virq);
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	chained_irq_exit(chip, desc);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int uniphier_pcie_config_legacy_irq(struct pcie_port *pp)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
2688c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
2698c2ecf20Sopenharmony_ci	struct device_node *np = pci->dev->of_node;
2708c2ecf20Sopenharmony_ci	struct device_node *np_intc;
2718c2ecf20Sopenharmony_ci	int ret = 0;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	np_intc = of_get_child_by_name(np, "legacy-interrupt-controller");
2748c2ecf20Sopenharmony_ci	if (!np_intc) {
2758c2ecf20Sopenharmony_ci		dev_err(pci->dev, "Failed to get legacy-interrupt-controller node\n");
2768c2ecf20Sopenharmony_ci		return -EINVAL;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	pp->irq = irq_of_parse_and_map(np_intc, 0);
2808c2ecf20Sopenharmony_ci	if (!pp->irq) {
2818c2ecf20Sopenharmony_ci		dev_err(pci->dev, "Failed to get an IRQ entry in legacy-interrupt-controller\n");
2828c2ecf20Sopenharmony_ci		ret = -EINVAL;
2838c2ecf20Sopenharmony_ci		goto out_put_node;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	priv->legacy_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX,
2878c2ecf20Sopenharmony_ci						&uniphier_intx_domain_ops, pp);
2888c2ecf20Sopenharmony_ci	if (!priv->legacy_irq_domain) {
2898c2ecf20Sopenharmony_ci		dev_err(pci->dev, "Failed to get INTx domain\n");
2908c2ecf20Sopenharmony_ci		ret = -ENODEV;
2918c2ecf20Sopenharmony_ci		goto out_put_node;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	irq_set_chained_handler_and_data(pp->irq, uniphier_pcie_irq_handler,
2958c2ecf20Sopenharmony_ci					 pp);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ciout_put_node:
2988c2ecf20Sopenharmony_ci	of_node_put(np_intc);
2998c2ecf20Sopenharmony_ci	return ret;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int uniphier_pcie_host_init(struct pcie_port *pp)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
3058c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
3068c2ecf20Sopenharmony_ci	int ret;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	ret = uniphier_pcie_config_legacy_irq(pp);
3098c2ecf20Sopenharmony_ci	if (ret)
3108c2ecf20Sopenharmony_ci		return ret;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	uniphier_pcie_irq_enable(priv);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	dw_pcie_setup_rc(pp);
3158c2ecf20Sopenharmony_ci	ret = uniphier_pcie_establish_link(pci);
3168c2ecf20Sopenharmony_ci	if (ret)
3178c2ecf20Sopenharmony_ci		return ret;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	dw_pcie_msi_init(pp);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic const struct dw_pcie_host_ops uniphier_pcie_host_ops = {
3258c2ecf20Sopenharmony_ci	.host_init = uniphier_pcie_host_init,
3268c2ecf20Sopenharmony_ci};
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv,
3298c2ecf20Sopenharmony_ci				  struct platform_device *pdev)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct dw_pcie *pci = &priv->pci;
3328c2ecf20Sopenharmony_ci	struct pcie_port *pp = &pci->pp;
3338c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3348c2ecf20Sopenharmony_ci	int ret;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	pp->ops = &uniphier_pcie_host_ops;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI)) {
3398c2ecf20Sopenharmony_ci		pp->msi_irq = platform_get_irq_byname(pdev, "msi");
3408c2ecf20Sopenharmony_ci		if (pp->msi_irq < 0)
3418c2ecf20Sopenharmony_ci			return pp->msi_irq;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	ret = dw_pcie_host_init(pp);
3458c2ecf20Sopenharmony_ci	if (ret) {
3468c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to initialize host (%d)\n", ret);
3478c2ecf20Sopenharmony_ci		return ret;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	int ret;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(priv->clk);
3588c2ecf20Sopenharmony_ci	if (ret)
3598c2ecf20Sopenharmony_ci		return ret;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	ret = reset_control_deassert(priv->rst);
3628c2ecf20Sopenharmony_ci	if (ret)
3638c2ecf20Sopenharmony_ci		goto out_clk_disable;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	uniphier_pcie_init_rc(priv);
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	ret = phy_init(priv->phy);
3688c2ecf20Sopenharmony_ci	if (ret)
3698c2ecf20Sopenharmony_ci		goto out_rst_assert;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	ret = uniphier_pcie_wait_rc(priv);
3728c2ecf20Sopenharmony_ci	if (ret)
3738c2ecf20Sopenharmony_ci		goto out_phy_exit;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return 0;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ciout_phy_exit:
3788c2ecf20Sopenharmony_ci	phy_exit(priv->phy);
3798c2ecf20Sopenharmony_ciout_rst_assert:
3808c2ecf20Sopenharmony_ci	reset_control_assert(priv->rst);
3818c2ecf20Sopenharmony_ciout_clk_disable:
3828c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->clk);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return ret;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic const struct dw_pcie_ops dw_pcie_ops = {
3888c2ecf20Sopenharmony_ci	.start_link = uniphier_pcie_establish_link,
3898c2ecf20Sopenharmony_ci	.stop_link = uniphier_pcie_stop_link,
3908c2ecf20Sopenharmony_ci	.link_up = uniphier_pcie_link_up,
3918c2ecf20Sopenharmony_ci};
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int uniphier_pcie_probe(struct platform_device *pdev)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
3968c2ecf20Sopenharmony_ci	struct uniphier_pcie_priv *priv;
3978c2ecf20Sopenharmony_ci	struct resource *res;
3988c2ecf20Sopenharmony_ci	int ret;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4018c2ecf20Sopenharmony_ci	if (!priv)
4028c2ecf20Sopenharmony_ci		return -ENOMEM;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	priv->pci.dev = dev;
4058c2ecf20Sopenharmony_ci	priv->pci.ops = &dw_pcie_ops;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
4088c2ecf20Sopenharmony_ci	priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
4098c2ecf20Sopenharmony_ci	if (IS_ERR(priv->pci.dbi_base))
4108c2ecf20Sopenharmony_ci		return PTR_ERR(priv->pci.dbi_base);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
4138c2ecf20Sopenharmony_ci	if (IS_ERR(priv->base))
4148c2ecf20Sopenharmony_ci		return PTR_ERR(priv->base);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	priv->clk = devm_clk_get(dev, NULL);
4178c2ecf20Sopenharmony_ci	if (IS_ERR(priv->clk))
4188c2ecf20Sopenharmony_ci		return PTR_ERR(priv->clk);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	priv->rst = devm_reset_control_get_shared(dev, NULL);
4218c2ecf20Sopenharmony_ci	if (IS_ERR(priv->rst))
4228c2ecf20Sopenharmony_ci		return PTR_ERR(priv->rst);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	priv->phy = devm_phy_optional_get(dev, "pcie-phy");
4258c2ecf20Sopenharmony_ci	if (IS_ERR(priv->phy))
4268c2ecf20Sopenharmony_ci		return PTR_ERR(priv->phy);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	ret = uniphier_pcie_host_enable(priv);
4318c2ecf20Sopenharmony_ci	if (ret)
4328c2ecf20Sopenharmony_ci		return ret;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return uniphier_add_pcie_port(priv, pdev);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistatic const struct of_device_id uniphier_pcie_match[] = {
4388c2ecf20Sopenharmony_ci	{ .compatible = "socionext,uniphier-pcie", },
4398c2ecf20Sopenharmony_ci	{ /* sentinel */ },
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic struct platform_driver uniphier_pcie_driver = {
4438c2ecf20Sopenharmony_ci	.probe  = uniphier_pcie_probe,
4448c2ecf20Sopenharmony_ci	.driver = {
4458c2ecf20Sopenharmony_ci		.name = "uniphier-pcie",
4468c2ecf20Sopenharmony_ci		.of_match_table = uniphier_pcie_match,
4478c2ecf20Sopenharmony_ci	},
4488c2ecf20Sopenharmony_ci};
4498c2ecf20Sopenharmony_cibuiltin_platform_driver(uniphier_pcie_driver);
450