13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * Rockchip AXI PCIe host controller driver
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright (c) 2016 Rockchip, Inc.
63d0407baSopenharmony_ci *
73d0407baSopenharmony_ci * Author: Shawn Lin <shawn.lin@rock-chips.com>
83d0407baSopenharmony_ci *         Wenrui Li <wenrui.li@rock-chips.com>
93d0407baSopenharmony_ci *
103d0407baSopenharmony_ci * Bits taken from Synopsys DesignWare Host controller driver and
113d0407baSopenharmony_ci * ARM PCI Host generic driver.
123d0407baSopenharmony_ci */
133d0407baSopenharmony_ci
143d0407baSopenharmony_ci#include <linux/clk.h>
153d0407baSopenharmony_ci#include <linux/delay.h>
163d0407baSopenharmony_ci#include <linux/gpio/consumer.h>
173d0407baSopenharmony_ci#include <linux/module.h>
183d0407baSopenharmony_ci#include <linux/of_pci.h>
193d0407baSopenharmony_ci#include <linux/phy/phy.h>
203d0407baSopenharmony_ci#include <linux/platform_device.h>
213d0407baSopenharmony_ci#include <linux/reset.h>
223d0407baSopenharmony_ci
233d0407baSopenharmony_ci#include "../pci.h"
243d0407baSopenharmony_ci#include "pcie-rockchip.h"
253d0407baSopenharmony_ci
263d0407baSopenharmony_ci#define RK_PCIE_LANES_THREE 3
273d0407baSopenharmony_ci#define RK_PCIE_LANES_FOUR 4
283d0407baSopenharmony_ci#define RK_PCIE_LINK_GEN_MAX 2
293d0407baSopenharmony_ci#define RK_PCIE_INIT_UDELAY 10
303d0407baSopenharmony_ci#define RK_PCIE_CFG_BIT_MASK 23
313d0407baSopenharmony_ci
323d0407baSopenharmony_ciint rockchip_pcie_get_phys(struct rockchip_pcie *rockchip)
333d0407baSopenharmony_ci{
343d0407baSopenharmony_ci    struct device *dev = rockchip->dev;
353d0407baSopenharmony_ci    struct phy *phy;
363d0407baSopenharmony_ci    char *name;
373d0407baSopenharmony_ci    u32 i;
383d0407baSopenharmony_ci
393d0407baSopenharmony_ci    phy = devm_phy_get(dev, "pcie-phy");
403d0407baSopenharmony_ci    if (!IS_ERR(phy)) {
413d0407baSopenharmony_ci        rockchip->legacy_phy = true;
423d0407baSopenharmony_ci        rockchip->phys[0] = phy;
433d0407baSopenharmony_ci        dev_warn(dev, "legacy phy model is deprecated!\n");
443d0407baSopenharmony_ci        return 0;
453d0407baSopenharmony_ci    }
463d0407baSopenharmony_ci
473d0407baSopenharmony_ci    if (PTR_ERR(phy) == -EPROBE_DEFER) {
483d0407baSopenharmony_ci        return PTR_ERR(phy);
493d0407baSopenharmony_ci    }
503d0407baSopenharmony_ci
513d0407baSopenharmony_ci    dev_dbg(dev, "missing legacy phy; search for per-lane PHY\n");
523d0407baSopenharmony_ci
533d0407baSopenharmony_ci    for (i = 0; i < MAX_LANE_NUM; i++) {
543d0407baSopenharmony_ci        name = kasprintf(GFP_KERNEL, "pcie-phy-%u", i);
553d0407baSopenharmony_ci        if (!name) {
563d0407baSopenharmony_ci            return -ENOMEM;
573d0407baSopenharmony_ci        }
583d0407baSopenharmony_ci
593d0407baSopenharmony_ci        phy = devm_of_phy_get(dev, dev->of_node, name);
603d0407baSopenharmony_ci        kfree(name);
613d0407baSopenharmony_ci
623d0407baSopenharmony_ci        if (IS_ERR(phy)) {
633d0407baSopenharmony_ci            if (PTR_ERR(phy) != -EPROBE_DEFER) {
643d0407baSopenharmony_ci                dev_err(dev, "missing phy for lane %d: %ld\n", i, PTR_ERR(phy));
653d0407baSopenharmony_ci            }
663d0407baSopenharmony_ci            return PTR_ERR(phy);
673d0407baSopenharmony_ci        }
683d0407baSopenharmony_ci
693d0407baSopenharmony_ci        rockchip->phys[i] = phy;
703d0407baSopenharmony_ci    }
713d0407baSopenharmony_ci
723d0407baSopenharmony_ci    return 0;
733d0407baSopenharmony_ci}
743d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_get_phys);
753d0407baSopenharmony_ci
763d0407baSopenharmony_ciint rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
773d0407baSopenharmony_ci{
783d0407baSopenharmony_ci    struct device *dev = rockchip->dev;
793d0407baSopenharmony_ci    struct platform_device *pdev = to_platform_device(dev);
803d0407baSopenharmony_ci    struct device_node *node = dev->of_node;
813d0407baSopenharmony_ci    struct resource *regs;
823d0407baSopenharmony_ci    int err;
833d0407baSopenharmony_ci
843d0407baSopenharmony_ci    if (rockchip->is_rc) {
853d0407baSopenharmony_ci        regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "axi-base");
863d0407baSopenharmony_ci        rockchip->reg_base = devm_pci_remap_cfg_resource(dev, regs);
873d0407baSopenharmony_ci        if (IS_ERR(rockchip->reg_base)) {
883d0407baSopenharmony_ci            return PTR_ERR(rockchip->reg_base);
893d0407baSopenharmony_ci        }
903d0407baSopenharmony_ci    } else {
913d0407baSopenharmony_ci        rockchip->mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem-base");
923d0407baSopenharmony_ci        if (!rockchip->mem_res) {
933d0407baSopenharmony_ci            return -EINVAL;
943d0407baSopenharmony_ci        }
953d0407baSopenharmony_ci    }
963d0407baSopenharmony_ci
973d0407baSopenharmony_ci    rockchip->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb-base");
983d0407baSopenharmony_ci    if (IS_ERR(rockchip->apb_base)) {
993d0407baSopenharmony_ci        return PTR_ERR(rockchip->apb_base);
1003d0407baSopenharmony_ci    }
1013d0407baSopenharmony_ci
1023d0407baSopenharmony_ci    err = rockchip_pcie_get_phys(rockchip);
1033d0407baSopenharmony_ci    if (err) {
1043d0407baSopenharmony_ci        return err;
1053d0407baSopenharmony_ci    }
1063d0407baSopenharmony_ci
1073d0407baSopenharmony_ci    rockchip->lanes = 1;
1083d0407baSopenharmony_ci    err = of_property_read_u32(node, "num-lanes", &rockchip->lanes);
1093d0407baSopenharmony_ci    if (!err &&
1103d0407baSopenharmony_ci        (rockchip->lanes == 0 || rockchip->lanes == RK_PCIE_LANES_THREE || rockchip->lanes > RK_PCIE_LANES_FOUR)) {
1113d0407baSopenharmony_ci        dev_warn(dev, "invalid num-lanes, default to use one lane\n");
1123d0407baSopenharmony_ci        rockchip->lanes = 1;
1133d0407baSopenharmony_ci    }
1143d0407baSopenharmony_ci
1153d0407baSopenharmony_ci    rockchip->link_gen = of_pci_get_max_link_speed(node);
1163d0407baSopenharmony_ci    if (rockchip->link_gen < 0 || rockchip->link_gen > RK_PCIE_LINK_GEN_MAX) {
1173d0407baSopenharmony_ci        rockchip->link_gen = RK_PCIE_LINK_GEN_MAX;
1183d0407baSopenharmony_ci    }
1193d0407baSopenharmony_ci
1203d0407baSopenharmony_ci    rockchip->core_rst = devm_reset_control_get_exclusive(dev, "core");
1213d0407baSopenharmony_ci    if (IS_ERR(rockchip->core_rst)) {
1223d0407baSopenharmony_ci        if (PTR_ERR(rockchip->core_rst) != -EPROBE_DEFER) {
1233d0407baSopenharmony_ci            dev_err(dev, "missing core reset property in node\n");
1243d0407baSopenharmony_ci        }
1253d0407baSopenharmony_ci        return PTR_ERR(rockchip->core_rst);
1263d0407baSopenharmony_ci    }
1273d0407baSopenharmony_ci
1283d0407baSopenharmony_ci    rockchip->mgmt_rst = devm_reset_control_get_exclusive(dev, "mgmt");
1293d0407baSopenharmony_ci    if (IS_ERR(rockchip->mgmt_rst)) {
1303d0407baSopenharmony_ci        if (PTR_ERR(rockchip->mgmt_rst) != -EPROBE_DEFER) {
1313d0407baSopenharmony_ci            dev_err(dev, "missing mgmt reset property in node\n");
1323d0407baSopenharmony_ci        }
1333d0407baSopenharmony_ci        return PTR_ERR(rockchip->mgmt_rst);
1343d0407baSopenharmony_ci    }
1353d0407baSopenharmony_ci
1363d0407baSopenharmony_ci    rockchip->mgmt_sticky_rst = devm_reset_control_get_exclusive(dev, "mgmt-sticky");
1373d0407baSopenharmony_ci    if (IS_ERR(rockchip->mgmt_sticky_rst)) {
1383d0407baSopenharmony_ci        if (PTR_ERR(rockchip->mgmt_sticky_rst) != -EPROBE_DEFER) {
1393d0407baSopenharmony_ci            dev_err(dev, "missing mgmt-sticky reset property in node\n");
1403d0407baSopenharmony_ci        }
1413d0407baSopenharmony_ci        return PTR_ERR(rockchip->mgmt_sticky_rst);
1423d0407baSopenharmony_ci    }
1433d0407baSopenharmony_ci
1443d0407baSopenharmony_ci    rockchip->pipe_rst = devm_reset_control_get_exclusive(dev, "pipe");
1453d0407baSopenharmony_ci    if (IS_ERR(rockchip->pipe_rst)) {
1463d0407baSopenharmony_ci        if (PTR_ERR(rockchip->pipe_rst) != -EPROBE_DEFER) {
1473d0407baSopenharmony_ci            dev_err(dev, "missing pipe reset property in node\n");
1483d0407baSopenharmony_ci        }
1493d0407baSopenharmony_ci        return PTR_ERR(rockchip->pipe_rst);
1503d0407baSopenharmony_ci    }
1513d0407baSopenharmony_ci
1523d0407baSopenharmony_ci    rockchip->pm_rst = devm_reset_control_get_exclusive(dev, "pm");
1533d0407baSopenharmony_ci    if (IS_ERR(rockchip->pm_rst)) {
1543d0407baSopenharmony_ci        if (PTR_ERR(rockchip->pm_rst) != -EPROBE_DEFER) {
1553d0407baSopenharmony_ci            dev_err(dev, "missing pm reset property in node\n");
1563d0407baSopenharmony_ci        }
1573d0407baSopenharmony_ci        return PTR_ERR(rockchip->pm_rst);
1583d0407baSopenharmony_ci    }
1593d0407baSopenharmony_ci
1603d0407baSopenharmony_ci    rockchip->pclk_rst = devm_reset_control_get_exclusive(dev, "pclk");
1613d0407baSopenharmony_ci    if (IS_ERR(rockchip->pclk_rst)) {
1623d0407baSopenharmony_ci        if (PTR_ERR(rockchip->pclk_rst) != -EPROBE_DEFER) {
1633d0407baSopenharmony_ci            dev_err(dev, "missing pclk reset property in node\n");
1643d0407baSopenharmony_ci        }
1653d0407baSopenharmony_ci        return PTR_ERR(rockchip->pclk_rst);
1663d0407baSopenharmony_ci    }
1673d0407baSopenharmony_ci
1683d0407baSopenharmony_ci    rockchip->aclk_rst = devm_reset_control_get_exclusive(dev, "aclk");
1693d0407baSopenharmony_ci    if (IS_ERR(rockchip->aclk_rst)) {
1703d0407baSopenharmony_ci        if (PTR_ERR(rockchip->aclk_rst) != -EPROBE_DEFER) {
1713d0407baSopenharmony_ci            dev_err(dev, "missing aclk reset property in node\n");
1723d0407baSopenharmony_ci        }
1733d0407baSopenharmony_ci        return PTR_ERR(rockchip->aclk_rst);
1743d0407baSopenharmony_ci    }
1753d0407baSopenharmony_ci
1763d0407baSopenharmony_ci    if (rockchip->is_rc) {
1773d0407baSopenharmony_ci        rockchip->ep_gpio = devm_gpiod_get_optional(dev, "ep", GPIOD_OUT_HIGH);
1783d0407baSopenharmony_ci        if (IS_ERR(rockchip->ep_gpio)) {
1793d0407baSopenharmony_ci            return dev_err_probe(dev, PTR_ERR(rockchip->ep_gpio), "failed to get ep GPIO\n");
1803d0407baSopenharmony_ci        }
1813d0407baSopenharmony_ci    }
1823d0407baSopenharmony_ci
1833d0407baSopenharmony_ci    rockchip->aclk_pcie = devm_clk_get(dev, "aclk");
1843d0407baSopenharmony_ci    if (IS_ERR(rockchip->aclk_pcie)) {
1853d0407baSopenharmony_ci        dev_err(dev, "aclk clock not found\n");
1863d0407baSopenharmony_ci        return PTR_ERR(rockchip->aclk_pcie);
1873d0407baSopenharmony_ci    }
1883d0407baSopenharmony_ci
1893d0407baSopenharmony_ci    rockchip->aclk_perf_pcie = devm_clk_get(dev, "aclk-perf");
1903d0407baSopenharmony_ci    if (IS_ERR(rockchip->aclk_perf_pcie)) {
1913d0407baSopenharmony_ci        dev_err(dev, "aclk_perf clock not found\n");
1923d0407baSopenharmony_ci        return PTR_ERR(rockchip->aclk_perf_pcie);
1933d0407baSopenharmony_ci    }
1943d0407baSopenharmony_ci
1953d0407baSopenharmony_ci    rockchip->hclk_pcie = devm_clk_get(dev, "hclk");
1963d0407baSopenharmony_ci    if (IS_ERR(rockchip->hclk_pcie)) {
1973d0407baSopenharmony_ci        dev_err(dev, "hclk clock not found\n");
1983d0407baSopenharmony_ci        return PTR_ERR(rockchip->hclk_pcie);
1993d0407baSopenharmony_ci    }
2003d0407baSopenharmony_ci
2013d0407baSopenharmony_ci    rockchip->clk_pcie_pm = devm_clk_get(dev, "pm");
2023d0407baSopenharmony_ci    if (IS_ERR(rockchip->clk_pcie_pm)) {
2033d0407baSopenharmony_ci        dev_err(dev, "pm clock not found\n");
2043d0407baSopenharmony_ci        return PTR_ERR(rockchip->clk_pcie_pm);
2053d0407baSopenharmony_ci    }
2063d0407baSopenharmony_ci
2073d0407baSopenharmony_ci    return 0;
2083d0407baSopenharmony_ci}
2093d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_parse_dt);
2103d0407baSopenharmony_ci
2113d0407baSopenharmony_ciint rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
2123d0407baSopenharmony_ci{
2133d0407baSopenharmony_ci    struct device *dev = rockchip->dev;
2143d0407baSopenharmony_ci    int err, i;
2153d0407baSopenharmony_ci    u32 regs;
2163d0407baSopenharmony_ci
2173d0407baSopenharmony_ci    err = reset_control_assert(rockchip->aclk_rst);
2183d0407baSopenharmony_ci    if (err) {
2193d0407baSopenharmony_ci        dev_err(dev, "assert aclk_rst err %d\n", err);
2203d0407baSopenharmony_ci        return err;
2213d0407baSopenharmony_ci    }
2223d0407baSopenharmony_ci
2233d0407baSopenharmony_ci    err = reset_control_assert(rockchip->pclk_rst);
2243d0407baSopenharmony_ci    if (err) {
2253d0407baSopenharmony_ci        dev_err(dev, "assert pclk_rst err %d\n", err);
2263d0407baSopenharmony_ci        return err;
2273d0407baSopenharmony_ci    }
2283d0407baSopenharmony_ci
2293d0407baSopenharmony_ci    err = reset_control_assert(rockchip->pm_rst);
2303d0407baSopenharmony_ci    if (err) {
2313d0407baSopenharmony_ci        dev_err(dev, "assert pm_rst err %d\n", err);
2323d0407baSopenharmony_ci        return err;
2333d0407baSopenharmony_ci    }
2343d0407baSopenharmony_ci
2353d0407baSopenharmony_ci    for (i = 0; i < MAX_LANE_NUM; i++) {
2363d0407baSopenharmony_ci        err = phy_init(rockchip->phys[i]);
2373d0407baSopenharmony_ci        if (err) {
2383d0407baSopenharmony_ci            dev_err(dev, "init phy%d err %d\n", i, err);
2393d0407baSopenharmony_ci            goto err_exit_phy;
2403d0407baSopenharmony_ci        }
2413d0407baSopenharmony_ci    }
2423d0407baSopenharmony_ci
2433d0407baSopenharmony_ci    err = reset_control_assert(rockchip->core_rst);
2443d0407baSopenharmony_ci    if (err) {
2453d0407baSopenharmony_ci        dev_err(dev, "assert core_rst err %d\n", err);
2463d0407baSopenharmony_ci        goto err_exit_phy;
2473d0407baSopenharmony_ci    }
2483d0407baSopenharmony_ci
2493d0407baSopenharmony_ci    err = reset_control_assert(rockchip->mgmt_rst);
2503d0407baSopenharmony_ci    if (err) {
2513d0407baSopenharmony_ci        dev_err(dev, "assert mgmt_rst err %d\n", err);
2523d0407baSopenharmony_ci        goto err_exit_phy;
2533d0407baSopenharmony_ci    }
2543d0407baSopenharmony_ci
2553d0407baSopenharmony_ci    err = reset_control_assert(rockchip->mgmt_sticky_rst);
2563d0407baSopenharmony_ci    if (err) {
2573d0407baSopenharmony_ci        dev_err(dev, "assert mgmt_sticky_rst err %d\n", err);
2583d0407baSopenharmony_ci        goto err_exit_phy;
2593d0407baSopenharmony_ci    }
2603d0407baSopenharmony_ci
2613d0407baSopenharmony_ci    err = reset_control_assert(rockchip->pipe_rst);
2623d0407baSopenharmony_ci    if (err) {
2633d0407baSopenharmony_ci        dev_err(dev, "assert pipe_rst err %d\n", err);
2643d0407baSopenharmony_ci        goto err_exit_phy;
2653d0407baSopenharmony_ci    }
2663d0407baSopenharmony_ci
2673d0407baSopenharmony_ci    udelay(RK_PCIE_INIT_UDELAY);
2683d0407baSopenharmony_ci
2693d0407baSopenharmony_ci    err = reset_control_deassert(rockchip->pm_rst);
2703d0407baSopenharmony_ci    if (err) {
2713d0407baSopenharmony_ci        dev_err(dev, "deassert pm_rst err %d\n", err);
2723d0407baSopenharmony_ci        goto err_exit_phy;
2733d0407baSopenharmony_ci    }
2743d0407baSopenharmony_ci
2753d0407baSopenharmony_ci    err = reset_control_deassert(rockchip->aclk_rst);
2763d0407baSopenharmony_ci    if (err) {
2773d0407baSopenharmony_ci        dev_err(dev, "deassert aclk_rst err %d\n", err);
2783d0407baSopenharmony_ci        goto err_exit_phy;
2793d0407baSopenharmony_ci    }
2803d0407baSopenharmony_ci
2813d0407baSopenharmony_ci    err = reset_control_deassert(rockchip->pclk_rst);
2823d0407baSopenharmony_ci    if (err) {
2833d0407baSopenharmony_ci        dev_err(dev, "deassert pclk_rst err %d\n", err);
2843d0407baSopenharmony_ci        goto err_exit_phy;
2853d0407baSopenharmony_ci    }
2863d0407baSopenharmony_ci
2873d0407baSopenharmony_ci    if (rockchip->link_gen == RK_PCIE_LINK_GEN_MAX) {
2883d0407baSopenharmony_ci        rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2, PCIE_CLIENT_CONFIG);
2893d0407baSopenharmony_ci    } else {
2903d0407baSopenharmony_ci        rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1, PCIE_CLIENT_CONFIG);
2913d0407baSopenharmony_ci    }
2923d0407baSopenharmony_ci
2933d0407baSopenharmony_ci    regs = PCIE_CLIENT_LINK_TRAIN_ENABLE | PCIE_CLIENT_ARI_ENABLE | PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes);
2943d0407baSopenharmony_ci
2953d0407baSopenharmony_ci    if (rockchip->is_rc) {
2963d0407baSopenharmony_ci        regs |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC;
2973d0407baSopenharmony_ci    } else {
2983d0407baSopenharmony_ci        regs |= PCIE_CLIENT_CONF_DISABLE | PCIE_CLIENT_MODE_EP;
2993d0407baSopenharmony_ci    }
3003d0407baSopenharmony_ci
3013d0407baSopenharmony_ci    rockchip_pcie_write(rockchip, regs, PCIE_CLIENT_CONFIG);
3023d0407baSopenharmony_ci
3033d0407baSopenharmony_ci    for (i = 0; i < MAX_LANE_NUM; i++) {
3043d0407baSopenharmony_ci        err = phy_power_on(rockchip->phys[i]);
3053d0407baSopenharmony_ci        if (err) {
3063d0407baSopenharmony_ci            dev_err(dev, "power on phy%d err %d\n", i, err);
3073d0407baSopenharmony_ci            goto err_power_off_phy;
3083d0407baSopenharmony_ci        }
3093d0407baSopenharmony_ci    }
3103d0407baSopenharmony_ci
3113d0407baSopenharmony_ci    /*
3123d0407baSopenharmony_ci     * Please don't reorder the deassert sequence of the following
3133d0407baSopenharmony_ci     * four reset pins.
3143d0407baSopenharmony_ci     */
3153d0407baSopenharmony_ci    err = reset_control_deassert(rockchip->mgmt_sticky_rst);
3163d0407baSopenharmony_ci    if (err) {
3173d0407baSopenharmony_ci        dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err);
3183d0407baSopenharmony_ci        goto err_power_off_phy;
3193d0407baSopenharmony_ci    }
3203d0407baSopenharmony_ci
3213d0407baSopenharmony_ci    err = reset_control_deassert(rockchip->core_rst);
3223d0407baSopenharmony_ci    if (err) {
3233d0407baSopenharmony_ci        dev_err(dev, "deassert core_rst err %d\n", err);
3243d0407baSopenharmony_ci        goto err_power_off_phy;
3253d0407baSopenharmony_ci    }
3263d0407baSopenharmony_ci
3273d0407baSopenharmony_ci    err = reset_control_deassert(rockchip->mgmt_rst);
3283d0407baSopenharmony_ci    if (err) {
3293d0407baSopenharmony_ci        dev_err(dev, "deassert mgmt_rst err %d\n", err);
3303d0407baSopenharmony_ci        goto err_power_off_phy;
3313d0407baSopenharmony_ci    }
3323d0407baSopenharmony_ci
3333d0407baSopenharmony_ci    err = reset_control_deassert(rockchip->pipe_rst);
3343d0407baSopenharmony_ci    if (err) {
3353d0407baSopenharmony_ci        dev_err(dev, "deassert pipe_rst err %d\n", err);
3363d0407baSopenharmony_ci        goto err_power_off_phy;
3373d0407baSopenharmony_ci    }
3383d0407baSopenharmony_ci
3393d0407baSopenharmony_ci    return 0;
3403d0407baSopenharmony_cierr_power_off_phy:
3413d0407baSopenharmony_ci    while (i--) {
3423d0407baSopenharmony_ci        phy_power_off(rockchip->phys[i]);
3433d0407baSopenharmony_ci    }
3443d0407baSopenharmony_ci    i = MAX_LANE_NUM;
3453d0407baSopenharmony_cierr_exit_phy:
3463d0407baSopenharmony_ci    while (i--) {
3473d0407baSopenharmony_ci        phy_exit(rockchip->phys[i]);
3483d0407baSopenharmony_ci    }
3493d0407baSopenharmony_ci    return err;
3503d0407baSopenharmony_ci}
3513d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_init_port);
3523d0407baSopenharmony_ci
3533d0407baSopenharmony_civoid rockchip_pcie_deinit_phys(struct rockchip_pcie *rockchip)
3543d0407baSopenharmony_ci{
3553d0407baSopenharmony_ci    int i;
3563d0407baSopenharmony_ci
3573d0407baSopenharmony_ci    for (i = 0; i < MAX_LANE_NUM; i++) {
3583d0407baSopenharmony_ci        /* inactive lanes are already powered off */
3593d0407baSopenharmony_ci        if (rockchip->lanes_map & BIT(i)) {
3603d0407baSopenharmony_ci            phy_power_off(rockchip->phys[i]);
3613d0407baSopenharmony_ci        }
3623d0407baSopenharmony_ci        phy_exit(rockchip->phys[i]);
3633d0407baSopenharmony_ci    }
3643d0407baSopenharmony_ci}
3653d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_deinit_phys);
3663d0407baSopenharmony_ci
3673d0407baSopenharmony_ciint rockchip_pcie_enable_clocks(struct rockchip_pcie *rockchip)
3683d0407baSopenharmony_ci{
3693d0407baSopenharmony_ci    struct device *dev = rockchip->dev;
3703d0407baSopenharmony_ci    int err;
3713d0407baSopenharmony_ci
3723d0407baSopenharmony_ci    err = clk_prepare_enable(rockchip->aclk_pcie);
3733d0407baSopenharmony_ci    if (err) {
3743d0407baSopenharmony_ci        dev_err(dev, "unable to enable aclk_pcie clock\n");
3753d0407baSopenharmony_ci        return err;
3763d0407baSopenharmony_ci    }
3773d0407baSopenharmony_ci
3783d0407baSopenharmony_ci    err = clk_prepare_enable(rockchip->aclk_perf_pcie);
3793d0407baSopenharmony_ci    if (err) {
3803d0407baSopenharmony_ci        dev_err(dev, "unable to enable aclk_perf_pcie clock\n");
3813d0407baSopenharmony_ci        goto err_aclk_perf_pcie;
3823d0407baSopenharmony_ci    }
3833d0407baSopenharmony_ci
3843d0407baSopenharmony_ci    err = clk_prepare_enable(rockchip->hclk_pcie);
3853d0407baSopenharmony_ci    if (err) {
3863d0407baSopenharmony_ci        dev_err(dev, "unable to enable hclk_pcie clock\n");
3873d0407baSopenharmony_ci        goto err_hclk_pcie;
3883d0407baSopenharmony_ci    }
3893d0407baSopenharmony_ci
3903d0407baSopenharmony_ci    err = clk_prepare_enable(rockchip->clk_pcie_pm);
3913d0407baSopenharmony_ci    if (err) {
3923d0407baSopenharmony_ci        dev_err(dev, "unable to enable clk_pcie_pm clock\n");
3933d0407baSopenharmony_ci        goto err_clk_pcie_pm;
3943d0407baSopenharmony_ci    }
3953d0407baSopenharmony_ci
3963d0407baSopenharmony_ci    return 0;
3973d0407baSopenharmony_ci
3983d0407baSopenharmony_cierr_clk_pcie_pm:
3993d0407baSopenharmony_ci    clk_disable_unprepare(rockchip->hclk_pcie);
4003d0407baSopenharmony_cierr_hclk_pcie:
4013d0407baSopenharmony_ci    clk_disable_unprepare(rockchip->aclk_perf_pcie);
4023d0407baSopenharmony_cierr_aclk_perf_pcie:
4033d0407baSopenharmony_ci    clk_disable_unprepare(rockchip->aclk_pcie);
4043d0407baSopenharmony_ci    return err;
4053d0407baSopenharmony_ci}
4063d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_enable_clocks);
4073d0407baSopenharmony_ci
4083d0407baSopenharmony_civoid rockchip_pcie_disable_clocks(void *data)
4093d0407baSopenharmony_ci{
4103d0407baSopenharmony_ci    struct rockchip_pcie *rockchip = data;
4113d0407baSopenharmony_ci
4123d0407baSopenharmony_ci    clk_disable_unprepare(rockchip->clk_pcie_pm);
4133d0407baSopenharmony_ci    clk_disable_unprepare(rockchip->hclk_pcie);
4143d0407baSopenharmony_ci    clk_disable_unprepare(rockchip->aclk_perf_pcie);
4153d0407baSopenharmony_ci    clk_disable_unprepare(rockchip->aclk_pcie);
4163d0407baSopenharmony_ci}
4173d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_disable_clocks);
4183d0407baSopenharmony_ci
4193d0407baSopenharmony_civoid rockchip_pcie_cfg_configuration_accesses(struct rockchip_pcie *rockchip, u32 type)
4203d0407baSopenharmony_ci{
4213d0407baSopenharmony_ci    u32 ob_desc_0;
4223d0407baSopenharmony_ci
4233d0407baSopenharmony_ci    /* Configuration Accesses for region 0 */
4243d0407baSopenharmony_ci    rockchip_pcie_write(rockchip, 0x0, PCIE_RC_BAR_CONF);
4253d0407baSopenharmony_ci
4263d0407baSopenharmony_ci    rockchip_pcie_write(rockchip, (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS), PCIE_CORE_OB_REGION_ADDR0);
4273d0407baSopenharmony_ci    rockchip_pcie_write(rockchip, RC_REGION_0_ADDR_TRANS_H, PCIE_CORE_OB_REGION_ADDR1);
4283d0407baSopenharmony_ci    ob_desc_0 = rockchip_pcie_read(rockchip, PCIE_CORE_OB_REGION_DESC0);
4293d0407baSopenharmony_ci    ob_desc_0 &= ~(RC_REGION_0_TYPE_MASK);
4303d0407baSopenharmony_ci    ob_desc_0 |= (type | (0x1 << RK_PCIE_CFG_BIT_MASK));
4313d0407baSopenharmony_ci    rockchip_pcie_write(rockchip, ob_desc_0, PCIE_CORE_OB_REGION_DESC0);
4323d0407baSopenharmony_ci    rockchip_pcie_write(rockchip, 0x0, PCIE_CORE_OB_REGION_DESC1);
4333d0407baSopenharmony_ci}
4343d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(rockchip_pcie_cfg_configuration_accesses);
4353d0407baSopenharmony_ci
4363d0407baSopenharmony_ciMODULE_AUTHOR("Rockchip Inc");
4373d0407baSopenharmony_ciMODULE_DESCRIPTION("Rockchip AXI PCIe driver");
4383d0407baSopenharmony_ciMODULE_LICENSE("GPL v2");
439