18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCIe host controller driver for Amlogic MESON SoCs
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2018 Amlogic, inc.
68c2ecf20Sopenharmony_ci * Author: Yue Wang <yue.wang@amlogic.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
128c2ecf20Sopenharmony_ci#include <linux/of_device.h>
138c2ecf20Sopenharmony_ci#include <linux/of_gpio.h>
148c2ecf20Sopenharmony_ci#include <linux/pci.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
168c2ecf20Sopenharmony_ci#include <linux/reset.h>
178c2ecf20Sopenharmony_ci#include <linux/resource.h>
188c2ecf20Sopenharmony_ci#include <linux/types.h>
198c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
208c2ecf20Sopenharmony_ci#include <linux/module.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "pcie-designware.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define to_meson_pcie(x) dev_get_drvdata((x)->dev)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define PCIE_CAP_MAX_PAYLOAD_SIZE(x)	((x) << 5)
278c2ecf20Sopenharmony_ci#define PCIE_CAP_MAX_READ_REQ_SIZE(x)	((x) << 12)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* PCIe specific config registers */
308c2ecf20Sopenharmony_ci#define PCIE_CFG0			0x0
318c2ecf20Sopenharmony_ci#define APP_LTSSM_ENABLE		BIT(7)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define PCIE_CFG_STATUS12		0x30
348c2ecf20Sopenharmony_ci#define IS_SMLH_LINK_UP(x)		((x) & (1 << 6))
358c2ecf20Sopenharmony_ci#define IS_RDLH_LINK_UP(x)		((x) & (1 << 16))
368c2ecf20Sopenharmony_ci#define IS_LTSSM_UP(x)			((((x) >> 10) & 0x1f) == 0x11)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define PCIE_CFG_STATUS17		0x44
398c2ecf20Sopenharmony_ci#define PM_CURRENT_STATE(x)		(((x) >> 7) & 0x1)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define WAIT_LINKUP_TIMEOUT		4000
428c2ecf20Sopenharmony_ci#define PORT_CLK_RATE			100000000UL
438c2ecf20Sopenharmony_ci#define MAX_PAYLOAD_SIZE		256
448c2ecf20Sopenharmony_ci#define MAX_READ_REQ_SIZE		256
458c2ecf20Sopenharmony_ci#define PCIE_RESET_DELAY		500
468c2ecf20Sopenharmony_ci#define PCIE_SHARED_RESET		1
478c2ecf20Sopenharmony_ci#define PCIE_NORMAL_RESET		0
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cienum pcie_data_rate {
508c2ecf20Sopenharmony_ci	PCIE_GEN1,
518c2ecf20Sopenharmony_ci	PCIE_GEN2,
528c2ecf20Sopenharmony_ci	PCIE_GEN3,
538c2ecf20Sopenharmony_ci	PCIE_GEN4
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistruct meson_pcie_clk_res {
578c2ecf20Sopenharmony_ci	struct clk *clk;
588c2ecf20Sopenharmony_ci	struct clk *port_clk;
598c2ecf20Sopenharmony_ci	struct clk *general_clk;
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistruct meson_pcie_rc_reset {
638c2ecf20Sopenharmony_ci	struct reset_control *port;
648c2ecf20Sopenharmony_ci	struct reset_control *apb;
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistruct meson_pcie {
688c2ecf20Sopenharmony_ci	struct dw_pcie pci;
698c2ecf20Sopenharmony_ci	void __iomem *cfg_base;
708c2ecf20Sopenharmony_ci	struct meson_pcie_clk_res clk_res;
718c2ecf20Sopenharmony_ci	struct meson_pcie_rc_reset mrst;
728c2ecf20Sopenharmony_ci	struct gpio_desc *reset_gpio;
738c2ecf20Sopenharmony_ci	struct phy *phy;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic struct reset_control *meson_pcie_get_reset(struct meson_pcie *mp,
778c2ecf20Sopenharmony_ci						  const char *id,
788c2ecf20Sopenharmony_ci						  u32 reset_type)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct device *dev = mp->pci.dev;
818c2ecf20Sopenharmony_ci	struct reset_control *reset;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (reset_type == PCIE_SHARED_RESET)
848c2ecf20Sopenharmony_ci		reset = devm_reset_control_get_shared(dev, id);
858c2ecf20Sopenharmony_ci	else
868c2ecf20Sopenharmony_ci		reset = devm_reset_control_get(dev, id);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return reset;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int meson_pcie_get_resets(struct meson_pcie *mp)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct meson_pcie_rc_reset *mrst = &mp->mrst;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	mrst->port = meson_pcie_get_reset(mp, "port", PCIE_NORMAL_RESET);
968c2ecf20Sopenharmony_ci	if (IS_ERR(mrst->port))
978c2ecf20Sopenharmony_ci		return PTR_ERR(mrst->port);
988c2ecf20Sopenharmony_ci	reset_control_deassert(mrst->port);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	mrst->apb = meson_pcie_get_reset(mp, "apb", PCIE_SHARED_RESET);
1018c2ecf20Sopenharmony_ci	if (IS_ERR(mrst->apb))
1028c2ecf20Sopenharmony_ci		return PTR_ERR(mrst->apb);
1038c2ecf20Sopenharmony_ci	reset_control_deassert(mrst->apb);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int meson_pcie_get_mems(struct platform_device *pdev,
1098c2ecf20Sopenharmony_ci			       struct meson_pcie *mp)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct dw_pcie *pci = &mp->pci;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
1148c2ecf20Sopenharmony_ci	if (IS_ERR(pci->dbi_base))
1158c2ecf20Sopenharmony_ci		return PTR_ERR(pci->dbi_base);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	mp->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
1188c2ecf20Sopenharmony_ci	if (IS_ERR(mp->cfg_base))
1198c2ecf20Sopenharmony_ci		return PTR_ERR(mp->cfg_base);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int meson_pcie_power_on(struct meson_pcie *mp)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	int ret = 0;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	ret = phy_init(mp->phy);
1298c2ecf20Sopenharmony_ci	if (ret)
1308c2ecf20Sopenharmony_ci		return ret;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ret = phy_power_on(mp->phy);
1338c2ecf20Sopenharmony_ci	if (ret) {
1348c2ecf20Sopenharmony_ci		phy_exit(mp->phy);
1358c2ecf20Sopenharmony_ci		return ret;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return 0;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic void meson_pcie_power_off(struct meson_pcie *mp)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	phy_power_off(mp->phy);
1448c2ecf20Sopenharmony_ci	phy_exit(mp->phy);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic int meson_pcie_reset(struct meson_pcie *mp)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	struct meson_pcie_rc_reset *mrst = &mp->mrst;
1508c2ecf20Sopenharmony_ci	int ret = 0;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	ret = phy_reset(mp->phy);
1538c2ecf20Sopenharmony_ci	if (ret)
1548c2ecf20Sopenharmony_ci		return ret;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	reset_control_assert(mrst->port);
1578c2ecf20Sopenharmony_ci	reset_control_assert(mrst->apb);
1588c2ecf20Sopenharmony_ci	udelay(PCIE_RESET_DELAY);
1598c2ecf20Sopenharmony_ci	reset_control_deassert(mrst->port);
1608c2ecf20Sopenharmony_ci	reset_control_deassert(mrst->apb);
1618c2ecf20Sopenharmony_ci	udelay(PCIE_RESET_DELAY);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return 0;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic inline struct clk *meson_pcie_probe_clock(struct device *dev,
1678c2ecf20Sopenharmony_ci						 const char *id, u64 rate)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct clk *clk;
1708c2ecf20Sopenharmony_ci	int ret;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	clk = devm_clk_get(dev, id);
1738c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
1748c2ecf20Sopenharmony_ci		return clk;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (rate) {
1778c2ecf20Sopenharmony_ci		ret = clk_set_rate(clk, rate);
1788c2ecf20Sopenharmony_ci		if (ret) {
1798c2ecf20Sopenharmony_ci			dev_err(dev, "set clk rate failed, ret = %d\n", ret);
1808c2ecf20Sopenharmony_ci			return ERR_PTR(ret);
1818c2ecf20Sopenharmony_ci		}
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(clk);
1858c2ecf20Sopenharmony_ci	if (ret) {
1868c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't enable clk\n");
1878c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	devm_add_action_or_reset(dev,
1918c2ecf20Sopenharmony_ci				 (void (*) (void *))clk_disable_unprepare,
1928c2ecf20Sopenharmony_ci				 clk);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return clk;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int meson_pcie_probe_clocks(struct meson_pcie *mp)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	struct device *dev = mp->pci.dev;
2008c2ecf20Sopenharmony_ci	struct meson_pcie_clk_res *res = &mp->clk_res;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	res->port_clk = meson_pcie_probe_clock(dev, "port", PORT_CLK_RATE);
2038c2ecf20Sopenharmony_ci	if (IS_ERR(res->port_clk))
2048c2ecf20Sopenharmony_ci		return PTR_ERR(res->port_clk);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	res->general_clk = meson_pcie_probe_clock(dev, "general", 0);
2078c2ecf20Sopenharmony_ci	if (IS_ERR(res->general_clk))
2088c2ecf20Sopenharmony_ci		return PTR_ERR(res->general_clk);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	res->clk = meson_pcie_probe_clock(dev, "pclk", 0);
2118c2ecf20Sopenharmony_ci	if (IS_ERR(res->clk))
2128c2ecf20Sopenharmony_ci		return PTR_ERR(res->clk);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return 0;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	return readl(mp->cfg_base + reg);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	writel(val, mp->cfg_base + reg);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic void meson_pcie_assert_reset(struct meson_pcie *mp)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(mp->reset_gpio, 1);
2308c2ecf20Sopenharmony_ci	udelay(500);
2318c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(mp->reset_gpio, 0);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic void meson_pcie_init_dw(struct meson_pcie *mp)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	u32 val;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	val = meson_cfg_readl(mp, PCIE_CFG0);
2398c2ecf20Sopenharmony_ci	val |= APP_LTSSM_ENABLE;
2408c2ecf20Sopenharmony_ci	meson_cfg_writel(mp, val, PCIE_CFG0);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int meson_size_to_payload(struct meson_pcie *mp, int size)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct device *dev = mp->pci.dev;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/*
2488c2ecf20Sopenharmony_ci	 * dwc supports 2^(val+7) payload size, which val is 0~5 default to 1.
2498c2ecf20Sopenharmony_ci	 * So if input size is not 2^order alignment or less than 2^7 or bigger
2508c2ecf20Sopenharmony_ci	 * than 2^12, just set to default size 2^(1+7).
2518c2ecf20Sopenharmony_ci	 */
2528c2ecf20Sopenharmony_ci	if (!is_power_of_2(size) || size < 128 || size > 4096) {
2538c2ecf20Sopenharmony_ci		dev_warn(dev, "payload size %d, set to default 256\n", size);
2548c2ecf20Sopenharmony_ci		return 1;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	return fls(size) - 8;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic void meson_set_max_payload(struct meson_pcie *mp, int size)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct dw_pcie *pci = &mp->pci;
2638c2ecf20Sopenharmony_ci	u32 val;
2648c2ecf20Sopenharmony_ci	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
2658c2ecf20Sopenharmony_ci	int max_payload_size = meson_size_to_payload(mp, size);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
2688c2ecf20Sopenharmony_ci	val &= ~PCI_EXP_DEVCTL_PAYLOAD;
2698c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
2728c2ecf20Sopenharmony_ci	val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
2738c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct dw_pcie *pci = &mp->pci;
2798c2ecf20Sopenharmony_ci	u32 val;
2808c2ecf20Sopenharmony_ci	u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
2818c2ecf20Sopenharmony_ci	int max_rd_req_size = meson_size_to_payload(mp, size);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
2848c2ecf20Sopenharmony_ci	val &= ~PCI_EXP_DEVCTL_READRQ;
2858c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
2888c2ecf20Sopenharmony_ci	val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
2898c2ecf20Sopenharmony_ci	dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int meson_pcie_establish_link(struct meson_pcie *mp)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct dw_pcie *pci = &mp->pci;
2958c2ecf20Sopenharmony_ci	struct pcie_port *pp = &pci->pp;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	meson_pcie_init_dw(mp);
2988c2ecf20Sopenharmony_ci	meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
2998c2ecf20Sopenharmony_ci	meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	dw_pcie_setup_rc(pp);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	meson_pcie_assert_reset(mp);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return dw_pcie_wait_for_link(pci);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
3098c2ecf20Sopenharmony_ci				  int where, int size, u32 *val)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	int ret;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	ret = pci_generic_config_read(bus, devfn, where, size, val);
3148c2ecf20Sopenharmony_ci	if (ret != PCIBIOS_SUCCESSFUL)
3158c2ecf20Sopenharmony_ci		return ret;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/*
3188c2ecf20Sopenharmony_ci	 * There is a bug in the MESON AXG PCIe controller whereby software
3198c2ecf20Sopenharmony_ci	 * cannot program the PCI_CLASS_DEVICE register, so we must fabricate
3208c2ecf20Sopenharmony_ci	 * the return value in the config accessors.
3218c2ecf20Sopenharmony_ci	 */
3228c2ecf20Sopenharmony_ci	if (where == PCI_CLASS_REVISION && size == 4)
3238c2ecf20Sopenharmony_ci		*val = (PCI_CLASS_BRIDGE_PCI << 16) | (*val & 0xffff);
3248c2ecf20Sopenharmony_ci	else if (where == PCI_CLASS_DEVICE && size == 2)
3258c2ecf20Sopenharmony_ci		*val = PCI_CLASS_BRIDGE_PCI;
3268c2ecf20Sopenharmony_ci	else if (where == PCI_CLASS_DEVICE && size == 1)
3278c2ecf20Sopenharmony_ci		*val = PCI_CLASS_BRIDGE_PCI & 0xff;
3288c2ecf20Sopenharmony_ci	else if (where == PCI_CLASS_DEVICE + 1 && size == 1)
3298c2ecf20Sopenharmony_ci		*val = (PCI_CLASS_BRIDGE_PCI >> 8) & 0xff;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic struct pci_ops meson_pci_ops = {
3358c2ecf20Sopenharmony_ci	.map_bus = dw_pcie_own_conf_map_bus,
3368c2ecf20Sopenharmony_ci	.read = meson_pcie_rd_own_conf,
3378c2ecf20Sopenharmony_ci	.write = pci_generic_config_write,
3388c2ecf20Sopenharmony_ci};
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int meson_pcie_link_up(struct dw_pcie *pci)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	struct meson_pcie *mp = to_meson_pcie(pci);
3438c2ecf20Sopenharmony_ci	struct device *dev = pci->dev;
3448c2ecf20Sopenharmony_ci	u32 speed_okay = 0;
3458c2ecf20Sopenharmony_ci	u32 cnt = 0;
3468c2ecf20Sopenharmony_ci	u32 state12, state17, smlh_up, ltssm_up, rdlh_up;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	do {
3498c2ecf20Sopenharmony_ci		state12 = meson_cfg_readl(mp, PCIE_CFG_STATUS12);
3508c2ecf20Sopenharmony_ci		state17 = meson_cfg_readl(mp, PCIE_CFG_STATUS17);
3518c2ecf20Sopenharmony_ci		smlh_up = IS_SMLH_LINK_UP(state12);
3528c2ecf20Sopenharmony_ci		rdlh_up = IS_RDLH_LINK_UP(state12);
3538c2ecf20Sopenharmony_ci		ltssm_up = IS_LTSSM_UP(state12);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		if (PM_CURRENT_STATE(state17) < PCIE_GEN3)
3568c2ecf20Sopenharmony_ci			speed_okay = 1;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		if (smlh_up)
3598c2ecf20Sopenharmony_ci			dev_dbg(dev, "smlh_link_up is on\n");
3608c2ecf20Sopenharmony_ci		if (rdlh_up)
3618c2ecf20Sopenharmony_ci			dev_dbg(dev, "rdlh_link_up is on\n");
3628c2ecf20Sopenharmony_ci		if (ltssm_up)
3638c2ecf20Sopenharmony_ci			dev_dbg(dev, "ltssm_up is on\n");
3648c2ecf20Sopenharmony_ci		if (speed_okay)
3658c2ecf20Sopenharmony_ci			dev_dbg(dev, "speed_okay\n");
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		if (smlh_up && rdlh_up && ltssm_up && speed_okay)
3688c2ecf20Sopenharmony_ci			return 1;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		cnt++;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		udelay(10);
3738c2ecf20Sopenharmony_ci	} while (cnt < WAIT_LINKUP_TIMEOUT);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	dev_err(dev, "error: wait linkup timeout\n");
3768c2ecf20Sopenharmony_ci	return 0;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int meson_pcie_host_init(struct pcie_port *pp)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
3828c2ecf20Sopenharmony_ci	struct meson_pcie *mp = to_meson_pcie(pci);
3838c2ecf20Sopenharmony_ci	int ret;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	pp->bridge->ops = &meson_pci_ops;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	ret = meson_pcie_establish_link(mp);
3888c2ecf20Sopenharmony_ci	if (ret)
3898c2ecf20Sopenharmony_ci		return ret;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	dw_pcie_msi_init(pp);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic const struct dw_pcie_host_ops meson_pcie_host_ops = {
3978c2ecf20Sopenharmony_ci	.host_init = meson_pcie_host_init,
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int meson_add_pcie_port(struct meson_pcie *mp,
4018c2ecf20Sopenharmony_ci			       struct platform_device *pdev)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct dw_pcie *pci = &mp->pci;
4048c2ecf20Sopenharmony_ci	struct pcie_port *pp = &pci->pp;
4058c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
4068c2ecf20Sopenharmony_ci	int ret;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_PCI_MSI)) {
4098c2ecf20Sopenharmony_ci		pp->msi_irq = platform_get_irq(pdev, 0);
4108c2ecf20Sopenharmony_ci		if (pp->msi_irq < 0)
4118c2ecf20Sopenharmony_ci			return pp->msi_irq;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	pp->ops = &meson_pcie_host_ops;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	ret = dw_pcie_host_init(pp);
4178c2ecf20Sopenharmony_ci	if (ret) {
4188c2ecf20Sopenharmony_ci		dev_err(dev, "failed to initialize host\n");
4198c2ecf20Sopenharmony_ci		return ret;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic const struct dw_pcie_ops dw_pcie_ops = {
4268c2ecf20Sopenharmony_ci	.link_up = meson_pcie_link_up,
4278c2ecf20Sopenharmony_ci};
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic int meson_pcie_probe(struct platform_device *pdev)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
4328c2ecf20Sopenharmony_ci	struct dw_pcie *pci;
4338c2ecf20Sopenharmony_ci	struct meson_pcie *mp;
4348c2ecf20Sopenharmony_ci	int ret;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	mp = devm_kzalloc(dev, sizeof(*mp), GFP_KERNEL);
4378c2ecf20Sopenharmony_ci	if (!mp)
4388c2ecf20Sopenharmony_ci		return -ENOMEM;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	pci = &mp->pci;
4418c2ecf20Sopenharmony_ci	pci->dev = dev;
4428c2ecf20Sopenharmony_ci	pci->ops = &dw_pcie_ops;
4438c2ecf20Sopenharmony_ci	pci->num_lanes = 1;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	mp->phy = devm_phy_get(dev, "pcie");
4468c2ecf20Sopenharmony_ci	if (IS_ERR(mp->phy)) {
4478c2ecf20Sopenharmony_ci		dev_err(dev, "get phy failed, %ld\n", PTR_ERR(mp->phy));
4488c2ecf20Sopenharmony_ci		return PTR_ERR(mp->phy);
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	mp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
4528c2ecf20Sopenharmony_ci	if (IS_ERR(mp->reset_gpio)) {
4538c2ecf20Sopenharmony_ci		dev_err(dev, "get reset gpio failed\n");
4548c2ecf20Sopenharmony_ci		return PTR_ERR(mp->reset_gpio);
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	ret = meson_pcie_get_resets(mp);
4588c2ecf20Sopenharmony_ci	if (ret) {
4598c2ecf20Sopenharmony_ci		dev_err(dev, "get reset resource failed, %d\n", ret);
4608c2ecf20Sopenharmony_ci		return ret;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	ret = meson_pcie_get_mems(pdev, mp);
4648c2ecf20Sopenharmony_ci	if (ret) {
4658c2ecf20Sopenharmony_ci		dev_err(dev, "get memory resource failed, %d\n", ret);
4668c2ecf20Sopenharmony_ci		return ret;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	ret = meson_pcie_power_on(mp);
4708c2ecf20Sopenharmony_ci	if (ret) {
4718c2ecf20Sopenharmony_ci		dev_err(dev, "phy power on failed, %d\n", ret);
4728c2ecf20Sopenharmony_ci		return ret;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	ret = meson_pcie_reset(mp);
4768c2ecf20Sopenharmony_ci	if (ret) {
4778c2ecf20Sopenharmony_ci		dev_err(dev, "reset failed, %d\n", ret);
4788c2ecf20Sopenharmony_ci		goto err_phy;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	ret = meson_pcie_probe_clocks(mp);
4828c2ecf20Sopenharmony_ci	if (ret) {
4838c2ecf20Sopenharmony_ci		dev_err(dev, "init clock resources failed, %d\n", ret);
4848c2ecf20Sopenharmony_ci		goto err_phy;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, mp);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	ret = meson_add_pcie_port(mp, pdev);
4908c2ecf20Sopenharmony_ci	if (ret < 0) {
4918c2ecf20Sopenharmony_ci		dev_err(dev, "Add PCIe port failed, %d\n", ret);
4928c2ecf20Sopenharmony_ci		goto err_phy;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	return 0;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cierr_phy:
4988c2ecf20Sopenharmony_ci	meson_pcie_power_off(mp);
4998c2ecf20Sopenharmony_ci	return ret;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic const struct of_device_id meson_pcie_of_match[] = {
5038c2ecf20Sopenharmony_ci	{
5048c2ecf20Sopenharmony_ci		.compatible = "amlogic,axg-pcie",
5058c2ecf20Sopenharmony_ci	},
5068c2ecf20Sopenharmony_ci	{
5078c2ecf20Sopenharmony_ci		.compatible = "amlogic,g12a-pcie",
5088c2ecf20Sopenharmony_ci	},
5098c2ecf20Sopenharmony_ci	{},
5108c2ecf20Sopenharmony_ci};
5118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, meson_pcie_of_match);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic struct platform_driver meson_pcie_driver = {
5148c2ecf20Sopenharmony_ci	.probe = meson_pcie_probe,
5158c2ecf20Sopenharmony_ci	.driver = {
5168c2ecf20Sopenharmony_ci		.name = "meson-pcie",
5178c2ecf20Sopenharmony_ci		.of_match_table = meson_pcie_of_match,
5188c2ecf20Sopenharmony_ci	},
5198c2ecf20Sopenharmony_ci};
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cimodule_platform_driver(meson_pcie_driver);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Yue Wang <yue.wang@amlogic.com>");
5248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic PCIe Controller driver");
5258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
526