18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Rockchip AXI PCIe host controller driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Rockchip, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Shawn Lin <shawn.lin@rock-chips.com> 88c2ecf20Sopenharmony_ci * Wenrui Li <wenrui.li@rock-chips.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Bits taken from Synopsys DesignWare Host controller driver and 118c2ecf20Sopenharmony_ci * ARM PCI Host generic driver. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 188c2ecf20Sopenharmony_ci#include <linux/of_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 "../pci.h" 248c2ecf20Sopenharmony_ci#include "pcie-rockchip.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciint rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 298c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 308c2ecf20Sopenharmony_ci struct device_node *node = dev->of_node; 318c2ecf20Sopenharmony_ci struct resource *regs; 328c2ecf20Sopenharmony_ci int err; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (rockchip->is_rc) { 358c2ecf20Sopenharmony_ci regs = platform_get_resource_byname(pdev, 368c2ecf20Sopenharmony_ci IORESOURCE_MEM, 378c2ecf20Sopenharmony_ci "axi-base"); 388c2ecf20Sopenharmony_ci rockchip->reg_base = devm_pci_remap_cfg_resource(dev, regs); 398c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->reg_base)) 408c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->reg_base); 418c2ecf20Sopenharmony_ci } else { 428c2ecf20Sopenharmony_ci rockchip->mem_res = 438c2ecf20Sopenharmony_ci platform_get_resource_byname(pdev, IORESOURCE_MEM, 448c2ecf20Sopenharmony_ci "mem-base"); 458c2ecf20Sopenharmony_ci if (!rockchip->mem_res) 468c2ecf20Sopenharmony_ci return -EINVAL; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci rockchip->apb_base = 508c2ecf20Sopenharmony_ci devm_platform_ioremap_resource_byname(pdev, "apb-base"); 518c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->apb_base)) 528c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->apb_base); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci err = rockchip_pcie_get_phys(rockchip); 558c2ecf20Sopenharmony_ci if (err) 568c2ecf20Sopenharmony_ci return err; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci rockchip->lanes = 1; 598c2ecf20Sopenharmony_ci err = of_property_read_u32(node, "num-lanes", &rockchip->lanes); 608c2ecf20Sopenharmony_ci if (!err && (rockchip->lanes == 0 || 618c2ecf20Sopenharmony_ci rockchip->lanes == 3 || 628c2ecf20Sopenharmony_ci rockchip->lanes > 4)) { 638c2ecf20Sopenharmony_ci dev_warn(dev, "invalid num-lanes, default to use one lane\n"); 648c2ecf20Sopenharmony_ci rockchip->lanes = 1; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci rockchip->link_gen = of_pci_get_max_link_speed(node); 688c2ecf20Sopenharmony_ci if (rockchip->link_gen < 0 || rockchip->link_gen > 2) 698c2ecf20Sopenharmony_ci rockchip->link_gen = 2; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci rockchip->core_rst = devm_reset_control_get_exclusive(dev, "core"); 728c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->core_rst)) { 738c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->core_rst) != -EPROBE_DEFER) 748c2ecf20Sopenharmony_ci dev_err(dev, "missing core reset property in node\n"); 758c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->core_rst); 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci rockchip->mgmt_rst = devm_reset_control_get_exclusive(dev, "mgmt"); 798c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->mgmt_rst)) { 808c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->mgmt_rst) != -EPROBE_DEFER) 818c2ecf20Sopenharmony_ci dev_err(dev, "missing mgmt reset property in node\n"); 828c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->mgmt_rst); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci rockchip->mgmt_sticky_rst = devm_reset_control_get_exclusive(dev, 868c2ecf20Sopenharmony_ci "mgmt-sticky"); 878c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->mgmt_sticky_rst)) { 888c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->mgmt_sticky_rst) != -EPROBE_DEFER) 898c2ecf20Sopenharmony_ci dev_err(dev, "missing mgmt-sticky reset property in node\n"); 908c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->mgmt_sticky_rst); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci rockchip->pipe_rst = devm_reset_control_get_exclusive(dev, "pipe"); 948c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->pipe_rst)) { 958c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->pipe_rst) != -EPROBE_DEFER) 968c2ecf20Sopenharmony_ci dev_err(dev, "missing pipe reset property in node\n"); 978c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->pipe_rst); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci rockchip->pm_rst = devm_reset_control_get_exclusive(dev, "pm"); 1018c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->pm_rst)) { 1028c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->pm_rst) != -EPROBE_DEFER) 1038c2ecf20Sopenharmony_ci dev_err(dev, "missing pm reset property in node\n"); 1048c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->pm_rst); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci rockchip->pclk_rst = devm_reset_control_get_exclusive(dev, "pclk"); 1088c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->pclk_rst)) { 1098c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->pclk_rst) != -EPROBE_DEFER) 1108c2ecf20Sopenharmony_ci dev_err(dev, "missing pclk reset property in node\n"); 1118c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->pclk_rst); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci rockchip->aclk_rst = devm_reset_control_get_exclusive(dev, "aclk"); 1158c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->aclk_rst)) { 1168c2ecf20Sopenharmony_ci if (PTR_ERR(rockchip->aclk_rst) != -EPROBE_DEFER) 1178c2ecf20Sopenharmony_ci dev_err(dev, "missing aclk reset property in node\n"); 1188c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->aclk_rst); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (rockchip->is_rc) { 1228c2ecf20Sopenharmony_ci rockchip->ep_gpio = devm_gpiod_get_optional(dev, "ep", 1238c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 1248c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->ep_gpio)) 1258c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(rockchip->ep_gpio), 1268c2ecf20Sopenharmony_ci "failed to get ep GPIO\n"); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci rockchip->aclk_pcie = devm_clk_get(dev, "aclk"); 1308c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->aclk_pcie)) { 1318c2ecf20Sopenharmony_ci dev_err(dev, "aclk clock not found\n"); 1328c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->aclk_pcie); 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci rockchip->aclk_perf_pcie = devm_clk_get(dev, "aclk-perf"); 1368c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->aclk_perf_pcie)) { 1378c2ecf20Sopenharmony_ci dev_err(dev, "aclk_perf clock not found\n"); 1388c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->aclk_perf_pcie); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci rockchip->hclk_pcie = devm_clk_get(dev, "hclk"); 1428c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->hclk_pcie)) { 1438c2ecf20Sopenharmony_ci dev_err(dev, "hclk clock not found\n"); 1448c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->hclk_pcie); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci rockchip->clk_pcie_pm = devm_clk_get(dev, "pm"); 1488c2ecf20Sopenharmony_ci if (IS_ERR(rockchip->clk_pcie_pm)) { 1498c2ecf20Sopenharmony_ci dev_err(dev, "pm clock not found\n"); 1508c2ecf20Sopenharmony_ci return PTR_ERR(rockchip->clk_pcie_pm); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_parse_dt); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define rockchip_pcie_read_addr(addr) rockchip_pcie_read(rockchip, addr) 1588c2ecf20Sopenharmony_ci/* 100 ms max wait time for PHY PLLs to lock */ 1598c2ecf20Sopenharmony_ci#define RK_PHY_PLL_LOCK_TIMEOUT_US 100000 1608c2ecf20Sopenharmony_ci/* Sleep should be less than 20ms */ 1618c2ecf20Sopenharmony_ci#define RK_PHY_PLL_LOCK_SLEEP_US 1000 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ciint rockchip_pcie_init_port(struct rockchip_pcie *rockchip) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 1668c2ecf20Sopenharmony_ci int err, i; 1678c2ecf20Sopenharmony_ci u32 regs; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci err = reset_control_assert(rockchip->aclk_rst); 1708c2ecf20Sopenharmony_ci if (err) { 1718c2ecf20Sopenharmony_ci dev_err(dev, "assert aclk_rst err %d\n", err); 1728c2ecf20Sopenharmony_ci return err; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci err = reset_control_assert(rockchip->pclk_rst); 1768c2ecf20Sopenharmony_ci if (err) { 1778c2ecf20Sopenharmony_ci dev_err(dev, "assert pclk_rst err %d\n", err); 1788c2ecf20Sopenharmony_ci return err; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci err = reset_control_assert(rockchip->pm_rst); 1828c2ecf20Sopenharmony_ci if (err) { 1838c2ecf20Sopenharmony_ci dev_err(dev, "assert pm_rst err %d\n", err); 1848c2ecf20Sopenharmony_ci return err; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LANE_NUM; i++) { 1888c2ecf20Sopenharmony_ci err = phy_init(rockchip->phys[i]); 1898c2ecf20Sopenharmony_ci if (err) { 1908c2ecf20Sopenharmony_ci dev_err(dev, "init phy%d err %d\n", i, err); 1918c2ecf20Sopenharmony_ci goto err_exit_phy; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci err = reset_control_assert(rockchip->core_rst); 1968c2ecf20Sopenharmony_ci if (err) { 1978c2ecf20Sopenharmony_ci dev_err(dev, "assert core_rst err %d\n", err); 1988c2ecf20Sopenharmony_ci goto err_exit_phy; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci err = reset_control_assert(rockchip->mgmt_rst); 2028c2ecf20Sopenharmony_ci if (err) { 2038c2ecf20Sopenharmony_ci dev_err(dev, "assert mgmt_rst err %d\n", err); 2048c2ecf20Sopenharmony_ci goto err_exit_phy; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci err = reset_control_assert(rockchip->mgmt_sticky_rst); 2088c2ecf20Sopenharmony_ci if (err) { 2098c2ecf20Sopenharmony_ci dev_err(dev, "assert mgmt_sticky_rst err %d\n", err); 2108c2ecf20Sopenharmony_ci goto err_exit_phy; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci err = reset_control_assert(rockchip->pipe_rst); 2148c2ecf20Sopenharmony_ci if (err) { 2158c2ecf20Sopenharmony_ci dev_err(dev, "assert pipe_rst err %d\n", err); 2168c2ecf20Sopenharmony_ci goto err_exit_phy; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci udelay(10); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci err = reset_control_deassert(rockchip->pm_rst); 2228c2ecf20Sopenharmony_ci if (err) { 2238c2ecf20Sopenharmony_ci dev_err(dev, "deassert pm_rst err %d\n", err); 2248c2ecf20Sopenharmony_ci goto err_exit_phy; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci err = reset_control_deassert(rockchip->aclk_rst); 2288c2ecf20Sopenharmony_ci if (err) { 2298c2ecf20Sopenharmony_ci dev_err(dev, "deassert aclk_rst err %d\n", err); 2308c2ecf20Sopenharmony_ci goto err_exit_phy; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci err = reset_control_deassert(rockchip->pclk_rst); 2348c2ecf20Sopenharmony_ci if (err) { 2358c2ecf20Sopenharmony_ci dev_err(dev, "deassert pclk_rst err %d\n", err); 2368c2ecf20Sopenharmony_ci goto err_exit_phy; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (rockchip->link_gen == 2) 2408c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2, 2418c2ecf20Sopenharmony_ci PCIE_CLIENT_CONFIG); 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1, 2448c2ecf20Sopenharmony_ci PCIE_CLIENT_CONFIG); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci regs = PCIE_CLIENT_LINK_TRAIN_ENABLE | PCIE_CLIENT_ARI_ENABLE | 2478c2ecf20Sopenharmony_ci PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (rockchip->is_rc) 2508c2ecf20Sopenharmony_ci regs |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC; 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci regs |= PCIE_CLIENT_CONF_DISABLE | PCIE_CLIENT_MODE_EP; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, regs, PCIE_CLIENT_CONFIG); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LANE_NUM; i++) { 2578c2ecf20Sopenharmony_ci err = phy_power_on(rockchip->phys[i]); 2588c2ecf20Sopenharmony_ci if (err) { 2598c2ecf20Sopenharmony_ci dev_err(dev, "power on phy%d err %d\n", i, err); 2608c2ecf20Sopenharmony_ci goto err_power_off_phy; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci err = readx_poll_timeout(rockchip_pcie_read_addr, 2658c2ecf20Sopenharmony_ci PCIE_CLIENT_SIDE_BAND_STATUS, 2668c2ecf20Sopenharmony_ci regs, !(regs & PCIE_CLIENT_PHY_ST), 2678c2ecf20Sopenharmony_ci RK_PHY_PLL_LOCK_SLEEP_US, 2688c2ecf20Sopenharmony_ci RK_PHY_PLL_LOCK_TIMEOUT_US); 2698c2ecf20Sopenharmony_ci if (err) { 2708c2ecf20Sopenharmony_ci dev_err(dev, "PHY PLLs could not lock, %d\n", err); 2718c2ecf20Sopenharmony_ci goto err_power_off_phy; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* 2758c2ecf20Sopenharmony_ci * Please don't reorder the deassert sequence of the following 2768c2ecf20Sopenharmony_ci * four reset pins. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci err = reset_control_deassert(rockchip->mgmt_sticky_rst); 2798c2ecf20Sopenharmony_ci if (err) { 2808c2ecf20Sopenharmony_ci dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err); 2818c2ecf20Sopenharmony_ci goto err_power_off_phy; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci err = reset_control_deassert(rockchip->core_rst); 2858c2ecf20Sopenharmony_ci if (err) { 2868c2ecf20Sopenharmony_ci dev_err(dev, "deassert core_rst err %d\n", err); 2878c2ecf20Sopenharmony_ci goto err_power_off_phy; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci err = reset_control_deassert(rockchip->mgmt_rst); 2918c2ecf20Sopenharmony_ci if (err) { 2928c2ecf20Sopenharmony_ci dev_err(dev, "deassert mgmt_rst err %d\n", err); 2938c2ecf20Sopenharmony_ci goto err_power_off_phy; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci err = reset_control_deassert(rockchip->pipe_rst); 2978c2ecf20Sopenharmony_ci if (err) { 2988c2ecf20Sopenharmony_ci dev_err(dev, "deassert pipe_rst err %d\n", err); 2998c2ecf20Sopenharmony_ci goto err_power_off_phy; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_cierr_power_off_phy: 3048c2ecf20Sopenharmony_ci while (i--) 3058c2ecf20Sopenharmony_ci phy_power_off(rockchip->phys[i]); 3068c2ecf20Sopenharmony_ci i = MAX_LANE_NUM; 3078c2ecf20Sopenharmony_cierr_exit_phy: 3088c2ecf20Sopenharmony_ci while (i--) 3098c2ecf20Sopenharmony_ci phy_exit(rockchip->phys[i]); 3108c2ecf20Sopenharmony_ci return err; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_init_port); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ciint rockchip_pcie_get_phys(struct rockchip_pcie *rockchip) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 3178c2ecf20Sopenharmony_ci struct phy *phy; 3188c2ecf20Sopenharmony_ci char *name; 3198c2ecf20Sopenharmony_ci u32 i; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci phy = devm_phy_get(dev, "pcie-phy"); 3228c2ecf20Sopenharmony_ci if (!IS_ERR(phy)) { 3238c2ecf20Sopenharmony_ci rockchip->legacy_phy = true; 3248c2ecf20Sopenharmony_ci rockchip->phys[0] = phy; 3258c2ecf20Sopenharmony_ci dev_warn(dev, "legacy phy model is deprecated!\n"); 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (PTR_ERR(phy) == -EPROBE_DEFER) 3308c2ecf20Sopenharmony_ci return PTR_ERR(phy); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci dev_dbg(dev, "missing legacy phy; search for per-lane PHY\n"); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LANE_NUM; i++) { 3358c2ecf20Sopenharmony_ci name = kasprintf(GFP_KERNEL, "pcie-phy-%u", i); 3368c2ecf20Sopenharmony_ci if (!name) 3378c2ecf20Sopenharmony_ci return -ENOMEM; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci phy = devm_of_phy_get(dev, dev->of_node, name); 3408c2ecf20Sopenharmony_ci kfree(name); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (IS_ERR(phy)) { 3438c2ecf20Sopenharmony_ci if (PTR_ERR(phy) != -EPROBE_DEFER) 3448c2ecf20Sopenharmony_ci dev_err(dev, "missing phy for lane %d: %ld\n", 3458c2ecf20Sopenharmony_ci i, PTR_ERR(phy)); 3468c2ecf20Sopenharmony_ci return PTR_ERR(phy); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci rockchip->phys[i] = phy; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_get_phys); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_civoid rockchip_pcie_deinit_phys(struct rockchip_pcie *rockchip) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci int i; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LANE_NUM; i++) { 3618c2ecf20Sopenharmony_ci /* inactive lanes are already powered off */ 3628c2ecf20Sopenharmony_ci if (rockchip->lanes_map & BIT(i)) 3638c2ecf20Sopenharmony_ci phy_power_off(rockchip->phys[i]); 3648c2ecf20Sopenharmony_ci phy_exit(rockchip->phys[i]); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_deinit_phys); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ciint rockchip_pcie_enable_clocks(struct rockchip_pcie *rockchip) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct device *dev = rockchip->dev; 3728c2ecf20Sopenharmony_ci int err; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci err = clk_prepare_enable(rockchip->aclk_pcie); 3758c2ecf20Sopenharmony_ci if (err) { 3768c2ecf20Sopenharmony_ci dev_err(dev, "unable to enable aclk_pcie clock\n"); 3778c2ecf20Sopenharmony_ci return err; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci err = clk_prepare_enable(rockchip->aclk_perf_pcie); 3818c2ecf20Sopenharmony_ci if (err) { 3828c2ecf20Sopenharmony_ci dev_err(dev, "unable to enable aclk_perf_pcie clock\n"); 3838c2ecf20Sopenharmony_ci goto err_aclk_perf_pcie; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci err = clk_prepare_enable(rockchip->hclk_pcie); 3878c2ecf20Sopenharmony_ci if (err) { 3888c2ecf20Sopenharmony_ci dev_err(dev, "unable to enable hclk_pcie clock\n"); 3898c2ecf20Sopenharmony_ci goto err_hclk_pcie; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci err = clk_prepare_enable(rockchip->clk_pcie_pm); 3938c2ecf20Sopenharmony_ci if (err) { 3948c2ecf20Sopenharmony_ci dev_err(dev, "unable to enable clk_pcie_pm clock\n"); 3958c2ecf20Sopenharmony_ci goto err_clk_pcie_pm; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cierr_clk_pcie_pm: 4018c2ecf20Sopenharmony_ci clk_disable_unprepare(rockchip->hclk_pcie); 4028c2ecf20Sopenharmony_cierr_hclk_pcie: 4038c2ecf20Sopenharmony_ci clk_disable_unprepare(rockchip->aclk_perf_pcie); 4048c2ecf20Sopenharmony_cierr_aclk_perf_pcie: 4058c2ecf20Sopenharmony_ci clk_disable_unprepare(rockchip->aclk_pcie); 4068c2ecf20Sopenharmony_ci return err; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_enable_clocks); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_civoid rockchip_pcie_disable_clocks(void *data) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip = data; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci clk_disable_unprepare(rockchip->clk_pcie_pm); 4158c2ecf20Sopenharmony_ci clk_disable_unprepare(rockchip->hclk_pcie); 4168c2ecf20Sopenharmony_ci clk_disable_unprepare(rockchip->aclk_perf_pcie); 4178c2ecf20Sopenharmony_ci clk_disable_unprepare(rockchip->aclk_pcie); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_disable_clocks); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_civoid rockchip_pcie_cfg_configuration_accesses( 4228c2ecf20Sopenharmony_ci struct rockchip_pcie *rockchip, u32 type) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci u32 ob_desc_0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Configuration Accesses for region 0 */ 4278c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, 0x0, PCIE_RC_BAR_CONF); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, 4308c2ecf20Sopenharmony_ci (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS), 4318c2ecf20Sopenharmony_ci PCIE_CORE_OB_REGION_ADDR0); 4328c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, RC_REGION_0_ADDR_TRANS_H, 4338c2ecf20Sopenharmony_ci PCIE_CORE_OB_REGION_ADDR1); 4348c2ecf20Sopenharmony_ci ob_desc_0 = rockchip_pcie_read(rockchip, PCIE_CORE_OB_REGION_DESC0); 4358c2ecf20Sopenharmony_ci ob_desc_0 &= ~(RC_REGION_0_TYPE_MASK); 4368c2ecf20Sopenharmony_ci ob_desc_0 |= (type | (0x1 << 23)); 4378c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, ob_desc_0, PCIE_CORE_OB_REGION_DESC0); 4388c2ecf20Sopenharmony_ci rockchip_pcie_write(rockchip, 0x0, PCIE_CORE_OB_REGION_DESC1); 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_cfg_configuration_accesses); 441