15fc35740SXincheng Zhang // SPDX-License-Identifier: GPL-2.0 25fc35740SXincheng Zhang /* 35fc35740SXincheng Zhang * DWC PCIe RC driver for UltraRISC SoCs 45fc35740SXincheng Zhang * 55fc35740SXincheng Zhang * Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd. 65fc35740SXincheng Zhang */ 75fc35740SXincheng Zhang 8e152c295SJia Wang #include <linux/clk.h> 95fc35740SXincheng Zhang #include <linux/kernel.h> 105fc35740SXincheng Zhang #include <linux/module.h> 115fc35740SXincheng Zhang #include <linux/of_device.h> 125fc35740SXincheng Zhang #include <linux/pci.h> 135fc35740SXincheng Zhang #include <linux/platform_device.h> 145fc35740SXincheng Zhang #include <linux/resource.h> 155fc35740SXincheng Zhang 165fc35740SXincheng Zhang #include "pcie-designware.h" 175fc35740SXincheng Zhang 185fc35740SXincheng Zhang #define PCIE_CUS_CORE 0x400000 195fc35740SXincheng Zhang 205fc35740SXincheng Zhang #define LTSSM_ENABLE BIT(7) 215fc35740SXincheng Zhang #define FAST_LINK_MODE BIT(12) 225fc35740SXincheng Zhang #define HOLD_PHY_RST BIT(14) 235fc35740SXincheng Zhang #define L1SUB_DISABLE BIT(15) 245fc35740SXincheng Zhang 255fc35740SXincheng Zhang #define ULTRARISC_PCIE_COMP_TIMEOUT_65_210MS 0x6 265fc35740SXincheng Zhang 27e152c295SJia Wang struct ultrarisc_pcie { 28e152c295SJia Wang struct dw_pcie pci; 29e152c295SJia Wang struct clk_bulk_data *clks; 30e152c295SJia Wang int num_clks; 31e152c295SJia Wang }; 32e152c295SJia Wang 335fc35740SXincheng Zhang static struct pci_ops ultrarisc_pci_ops = { 345fc35740SXincheng Zhang .map_bus = dw_pcie_own_conf_map_bus, 355fc35740SXincheng Zhang .read = pci_generic_config_read32, 365fc35740SXincheng Zhang .write = pci_generic_config_write32, 375fc35740SXincheng Zhang }; 385fc35740SXincheng Zhang 395fc35740SXincheng Zhang static int ultrarisc_pcie_host_init(struct dw_pcie_rp *pp) 405fc35740SXincheng Zhang { 415fc35740SXincheng Zhang struct dw_pcie *pci = to_dw_pcie_from_pp(pp); 425fc35740SXincheng Zhang struct pci_host_bridge *bridge = pp->bridge; 435fc35740SXincheng Zhang u8 cap_exp; 445fc35740SXincheng Zhang u32 val; 455fc35740SXincheng Zhang 465fc35740SXincheng Zhang bridge->ops = &ultrarisc_pci_ops; 475fc35740SXincheng Zhang 485fc35740SXincheng Zhang if (dw_pcie_link_up(pci)) 495fc35740SXincheng Zhang return 0; 505fc35740SXincheng Zhang 515fc35740SXincheng Zhang val = dw_pcie_readl_dbi(pci, PCIE_CUS_CORE); 525fc35740SXincheng Zhang val &= ~FAST_LINK_MODE; 535fc35740SXincheng Zhang dw_pcie_writel_dbi(pci, PCIE_CUS_CORE, val); 545fc35740SXincheng Zhang 555fc35740SXincheng Zhang val = dw_pcie_readl_dbi(pci, PCIE_TIMER_CTRL_MAX_FUNC_NUM); 565fc35740SXincheng Zhang FIELD_MODIFY(PORT_FLT_SF_MASK, &val, PORT_FLT_SF_VAL_64); 575fc35740SXincheng Zhang dw_pcie_writel_dbi(pci, PCIE_TIMER_CTRL_MAX_FUNC_NUM, val); 585fc35740SXincheng Zhang 595fc35740SXincheng Zhang cap_exp = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); 605fc35740SXincheng Zhang val = dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_LNKCTL2); 615fc35740SXincheng Zhang FIELD_MODIFY(PCI_EXP_LNKCTL2_TLS, &val, PCI_EXP_LNKCTL2_TLS_16_0GT); 625fc35740SXincheng Zhang dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCTL2, val); 635fc35740SXincheng Zhang 645fc35740SXincheng Zhang val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE); 655fc35740SXincheng Zhang FIELD_MODIFY(PORT_LINK_NUM_MASK, &val, 0); 665fc35740SXincheng Zhang dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val); 675fc35740SXincheng Zhang 685fc35740SXincheng Zhang val = dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_DEVCTL2); 695fc35740SXincheng Zhang FIELD_MODIFY(PCI_EXP_DEVCTL2_COMP_TIMEOUT, &val, 705fc35740SXincheng Zhang ULTRARISC_PCIE_COMP_TIMEOUT_65_210MS); 715fc35740SXincheng Zhang dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_DEVCTL2, val); 725fc35740SXincheng Zhang 735fc35740SXincheng Zhang val = dw_pcie_readl_dbi(pci, PCIE_CUS_CORE); 745fc35740SXincheng Zhang val &= ~(HOLD_PHY_RST | L1SUB_DISABLE); 755fc35740SXincheng Zhang dw_pcie_writel_dbi(pci, PCIE_CUS_CORE, val); 765fc35740SXincheng Zhang 775fc35740SXincheng Zhang return 0; 785fc35740SXincheng Zhang } 795fc35740SXincheng Zhang 805fc35740SXincheng Zhang static void ultrarisc_pcie_pme_turn_off(struct dw_pcie_rp *pp) 815fc35740SXincheng Zhang { 825fc35740SXincheng Zhang /* 835fc35740SXincheng Zhang * DP1000 does not support sending PME_Turn_Off from the RC. 845fc35740SXincheng Zhang * Keep this callback empty to skip the generic MSG TLP path. 855fc35740SXincheng Zhang */ 865fc35740SXincheng Zhang } 875fc35740SXincheng Zhang 885fc35740SXincheng Zhang static const struct dw_pcie_host_ops ultrarisc_pcie_host_ops = { 895fc35740SXincheng Zhang .init = ultrarisc_pcie_host_init, 905fc35740SXincheng Zhang .pme_turn_off = ultrarisc_pcie_pme_turn_off, 915fc35740SXincheng Zhang }; 925fc35740SXincheng Zhang 935fc35740SXincheng Zhang static int ultrarisc_pcie_start_link(struct dw_pcie *pci) 945fc35740SXincheng Zhang { 955fc35740SXincheng Zhang u32 val; 965fc35740SXincheng Zhang 975fc35740SXincheng Zhang val = dw_pcie_readl_dbi(pci, PCIE_CUS_CORE); 985fc35740SXincheng Zhang val |= LTSSM_ENABLE; 995fc35740SXincheng Zhang dw_pcie_writel_dbi(pci, PCIE_CUS_CORE, val); 1005fc35740SXincheng Zhang 1015fc35740SXincheng Zhang return 0; 1025fc35740SXincheng Zhang } 1035fc35740SXincheng Zhang 1045fc35740SXincheng Zhang static const struct dw_pcie_ops dw_pcie_ops = { 1055fc35740SXincheng Zhang .start_link = ultrarisc_pcie_start_link, 1065fc35740SXincheng Zhang }; 1075fc35740SXincheng Zhang 108e152c295SJia Wang static int ultrarisc_pcie_enable_clks(struct ultrarisc_pcie *ultra) 109e152c295SJia Wang { 110e152c295SJia Wang return clk_bulk_prepare_enable(ultra->num_clks, ultra->clks); 111e152c295SJia Wang } 112e152c295SJia Wang 113e152c295SJia Wang static void ultrarisc_pcie_disable_clks(void *data) 114e152c295SJia Wang { 115e152c295SJia Wang struct ultrarisc_pcie *ultra = data; 116e152c295SJia Wang 117e152c295SJia Wang clk_bulk_disable_unprepare(ultra->num_clks, ultra->clks); 118e152c295SJia Wang } 119e152c295SJia Wang 120e152c295SJia Wang static int ultrarisc_pcie_init_clks(struct ultrarisc_pcie *ultra) 121e152c295SJia Wang { 122e152c295SJia Wang struct device *dev = ultra->pci.dev; 123e152c295SJia Wang int ret; 124e152c295SJia Wang 125e152c295SJia Wang ultra->num_clks = devm_clk_bulk_get_all(dev, &ultra->clks); 126e152c295SJia Wang if (ultra->num_clks < 0) 127e152c295SJia Wang return dev_err_probe(dev, ultra->num_clks, "Failed to get clocks\n"); 128e152c295SJia Wang 129e152c295SJia Wang ret = ultrarisc_pcie_enable_clks(ultra); 130e152c295SJia Wang if (ret) 131e152c295SJia Wang return dev_err_probe(dev, ret, "Failed to enable clocks\n"); 132e152c295SJia Wang 133e152c295SJia Wang return devm_add_action_or_reset(dev, ultrarisc_pcie_disable_clks, ultra); 134e152c295SJia Wang } 135e152c295SJia Wang 1365fc35740SXincheng Zhang static int ultrarisc_pcie_probe(struct platform_device *pdev) 1375fc35740SXincheng Zhang { 138e152c295SJia Wang struct ultrarisc_pcie *ultra; 1395fc35740SXincheng Zhang struct device *dev = &pdev->dev; 1405fc35740SXincheng Zhang struct dw_pcie_rp *pp; 1415fc35740SXincheng Zhang struct dw_pcie *pci; 1425fc35740SXincheng Zhang int ret; 1435fc35740SXincheng Zhang 144e152c295SJia Wang ultra = devm_kzalloc(dev, sizeof(*ultra), GFP_KERNEL); 145e152c295SJia Wang if (!ultra) 1465fc35740SXincheng Zhang return -ENOMEM; 1475fc35740SXincheng Zhang 148e152c295SJia Wang pci = &ultra->pci; 1495fc35740SXincheng Zhang pci->dev = dev; 1505fc35740SXincheng Zhang pci->ops = &dw_pcie_ops; 1515fc35740SXincheng Zhang 1525fc35740SXincheng Zhang /* Set a default value suitable for at most 16 in and 16 out windows */ 1535fc35740SXincheng Zhang pci->atu_size = SZ_8K; 1545fc35740SXincheng Zhang 1555fc35740SXincheng Zhang pp = &pci->pp; 1565fc35740SXincheng Zhang 157e152c295SJia Wang platform_set_drvdata(pdev, ultra); 158e152c295SJia Wang 159e152c295SJia Wang ret = ultrarisc_pcie_init_clks(ultra); 160e152c295SJia Wang if (ret) 161e152c295SJia Wang return ret; 1625fc35740SXincheng Zhang 1635fc35740SXincheng Zhang pp->num_vectors = MAX_MSI_IRQS; 1645fc35740SXincheng Zhang /* No L2/L3 Ready indication is available on this platform */ 1655fc35740SXincheng Zhang pp->skip_l23_ready = true; 1665fc35740SXincheng Zhang pp->ops = &ultrarisc_pcie_host_ops; 1675fc35740SXincheng Zhang 1685fc35740SXincheng Zhang ret = dw_pcie_host_init(pp); 1695fc35740SXincheng Zhang if (ret) { 1705fc35740SXincheng Zhang dev_err(dev, "Failed to initialize host\n"); 1715fc35740SXincheng Zhang return ret; 1725fc35740SXincheng Zhang } 1735fc35740SXincheng Zhang 1745fc35740SXincheng Zhang return 0; 1755fc35740SXincheng Zhang } 1765fc35740SXincheng Zhang 1775fc35740SXincheng Zhang static int ultrarisc_pcie_suspend_noirq(struct device *dev) 1785fc35740SXincheng Zhang { 179e152c295SJia Wang struct ultrarisc_pcie *ultra = dev_get_drvdata(dev); 180e152c295SJia Wang struct dw_pcie *pci = &ultra->pci; 181e152c295SJia Wang int ret; 1825fc35740SXincheng Zhang 183e152c295SJia Wang /* 184e152c295SJia Wang * A failed resume leaves the DWC suspended and the clocks disabled. 185e152c295SJia Wang * A later suspend must not access the controller or disable them again. 186e152c295SJia Wang */ 187e152c295SJia Wang if (pci->suspended) 188e152c295SJia Wang return 0; 189e152c295SJia Wang 190e152c295SJia Wang ret = dw_pcie_suspend_noirq(pci); 191e152c295SJia Wang if (ret) 192e152c295SJia Wang return ret; 193e152c295SJia Wang 194e152c295SJia Wang if (pci->suspended) 195e152c295SJia Wang ultrarisc_pcie_disable_clks(ultra); 196e152c295SJia Wang 197e152c295SJia Wang return 0; 1985fc35740SXincheng Zhang } 1995fc35740SXincheng Zhang 2005fc35740SXincheng Zhang static int ultrarisc_pcie_resume_noirq(struct device *dev) 2015fc35740SXincheng Zhang { 202e152c295SJia Wang struct ultrarisc_pcie *ultra = dev_get_drvdata(dev); 203e152c295SJia Wang struct dw_pcie *pci = &ultra->pci; 204e152c295SJia Wang int ret; 2055fc35740SXincheng Zhang 206e152c295SJia Wang if (pci->suspended) { 207e152c295SJia Wang ret = ultrarisc_pcie_enable_clks(ultra); 208e152c295SJia Wang if (ret) 209e152c295SJia Wang return ret; 210e152c295SJia Wang 211e152c295SJia Wang ret = dw_pcie_resume_noirq(pci); 212e152c295SJia Wang if (ret) { 213e152c295SJia Wang ultrarisc_pcie_disable_clks(ultra); 214e152c295SJia Wang return ret; 215e152c295SJia Wang } 216e152c295SJia Wang } 217e152c295SJia Wang 218e152c295SJia Wang return 0; 2195fc35740SXincheng Zhang } 2205fc35740SXincheng Zhang 2215fc35740SXincheng Zhang static const struct dev_pm_ops ultrarisc_pcie_pm_ops = { 2225fc35740SXincheng Zhang NOIRQ_SYSTEM_SLEEP_PM_OPS(ultrarisc_pcie_suspend_noirq, 2235fc35740SXincheng Zhang ultrarisc_pcie_resume_noirq) 2245fc35740SXincheng Zhang }; 2255fc35740SXincheng Zhang 2265fc35740SXincheng Zhang static const struct of_device_id ultrarisc_pcie_of_match[] = { 2275fc35740SXincheng Zhang { 2285fc35740SXincheng Zhang .compatible = "ultrarisc,dp1000-pcie", 2295fc35740SXincheng Zhang }, 2305fc35740SXincheng Zhang {}, 2315fc35740SXincheng Zhang }; 2325fc35740SXincheng Zhang MODULE_DEVICE_TABLE(of, ultrarisc_pcie_of_match); 2335fc35740SXincheng Zhang 2345fc35740SXincheng Zhang static struct platform_driver ultrarisc_pcie_driver = { 2355fc35740SXincheng Zhang .driver = { 2365fc35740SXincheng Zhang .name = "ultrarisc-pcie", 2375fc35740SXincheng Zhang .of_match_table = ultrarisc_pcie_of_match, 2385fc35740SXincheng Zhang .suppress_bind_attrs = true, 2395fc35740SXincheng Zhang .pm = &ultrarisc_pcie_pm_ops, 2405fc35740SXincheng Zhang }, 2415fc35740SXincheng Zhang .probe = ultrarisc_pcie_probe, 2425fc35740SXincheng Zhang }; 243*22a415e6SJia Wang module_platform_driver(ultrarisc_pcie_driver); 2445fc35740SXincheng Zhang 2455fc35740SXincheng Zhang MODULE_DESCRIPTION("UltraRISC DP1000 DWC PCIe host controller"); 2465fc35740SXincheng Zhang MODULE_LICENSE("GPL"); 247