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