cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pcie-rockchip.c (11201B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Rockchip AXI PCIe host controller driver
      4 *
      5 * Copyright (c) 2016 Rockchip, Inc.
      6 *
      7 * Author: Shawn Lin <shawn.lin@rock-chips.com>
      8 *         Wenrui Li <wenrui.li@rock-chips.com>
      9 *
     10 * Bits taken from Synopsys DesignWare Host controller driver and
     11 * ARM PCI Host generic driver.
     12 */
     13
     14#include <linux/clk.h>
     15#include <linux/delay.h>
     16#include <linux/gpio/consumer.h>
     17#include <linux/of_pci.h>
     18#include <linux/phy/phy.h>
     19#include <linux/platform_device.h>
     20#include <linux/reset.h>
     21
     22#include "../pci.h"
     23#include "pcie-rockchip.h"
     24
     25int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
     26{
     27	struct device *dev = rockchip->dev;
     28	struct platform_device *pdev = to_platform_device(dev);
     29	struct device_node *node = dev->of_node;
     30	struct resource *regs;
     31	int err;
     32
     33	if (rockchip->is_rc) {
     34		regs = platform_get_resource_byname(pdev,
     35						    IORESOURCE_MEM,
     36						    "axi-base");
     37		rockchip->reg_base = devm_pci_remap_cfg_resource(dev, regs);
     38		if (IS_ERR(rockchip->reg_base))
     39			return PTR_ERR(rockchip->reg_base);
     40	} else {
     41		rockchip->mem_res =
     42			platform_get_resource_byname(pdev, IORESOURCE_MEM,
     43						     "mem-base");
     44		if (!rockchip->mem_res)
     45			return -EINVAL;
     46	}
     47
     48	rockchip->apb_base =
     49		devm_platform_ioremap_resource_byname(pdev, "apb-base");
     50	if (IS_ERR(rockchip->apb_base))
     51		return PTR_ERR(rockchip->apb_base);
     52
     53	err = rockchip_pcie_get_phys(rockchip);
     54	if (err)
     55		return err;
     56
     57	rockchip->lanes = 1;
     58	err = of_property_read_u32(node, "num-lanes", &rockchip->lanes);
     59	if (!err && (rockchip->lanes == 0 ||
     60		     rockchip->lanes == 3 ||
     61		     rockchip->lanes > 4)) {
     62		dev_warn(dev, "invalid num-lanes, default to use one lane\n");
     63		rockchip->lanes = 1;
     64	}
     65
     66	rockchip->link_gen = of_pci_get_max_link_speed(node);
     67	if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
     68		rockchip->link_gen = 2;
     69
     70	rockchip->core_rst = devm_reset_control_get_exclusive(dev, "core");
     71	if (IS_ERR(rockchip->core_rst)) {
     72		if (PTR_ERR(rockchip->core_rst) != -EPROBE_DEFER)
     73			dev_err(dev, "missing core reset property in node\n");
     74		return PTR_ERR(rockchip->core_rst);
     75	}
     76
     77	rockchip->mgmt_rst = devm_reset_control_get_exclusive(dev, "mgmt");
     78	if (IS_ERR(rockchip->mgmt_rst)) {
     79		if (PTR_ERR(rockchip->mgmt_rst) != -EPROBE_DEFER)
     80			dev_err(dev, "missing mgmt reset property in node\n");
     81		return PTR_ERR(rockchip->mgmt_rst);
     82	}
     83
     84	rockchip->mgmt_sticky_rst = devm_reset_control_get_exclusive(dev,
     85								"mgmt-sticky");
     86	if (IS_ERR(rockchip->mgmt_sticky_rst)) {
     87		if (PTR_ERR(rockchip->mgmt_sticky_rst) != -EPROBE_DEFER)
     88			dev_err(dev, "missing mgmt-sticky reset property in node\n");
     89		return PTR_ERR(rockchip->mgmt_sticky_rst);
     90	}
     91
     92	rockchip->pipe_rst = devm_reset_control_get_exclusive(dev, "pipe");
     93	if (IS_ERR(rockchip->pipe_rst)) {
     94		if (PTR_ERR(rockchip->pipe_rst) != -EPROBE_DEFER)
     95			dev_err(dev, "missing pipe reset property in node\n");
     96		return PTR_ERR(rockchip->pipe_rst);
     97	}
     98
     99	rockchip->pm_rst = devm_reset_control_get_exclusive(dev, "pm");
    100	if (IS_ERR(rockchip->pm_rst)) {
    101		if (PTR_ERR(rockchip->pm_rst) != -EPROBE_DEFER)
    102			dev_err(dev, "missing pm reset property in node\n");
    103		return PTR_ERR(rockchip->pm_rst);
    104	}
    105
    106	rockchip->pclk_rst = devm_reset_control_get_exclusive(dev, "pclk");
    107	if (IS_ERR(rockchip->pclk_rst)) {
    108		if (PTR_ERR(rockchip->pclk_rst) != -EPROBE_DEFER)
    109			dev_err(dev, "missing pclk reset property in node\n");
    110		return PTR_ERR(rockchip->pclk_rst);
    111	}
    112
    113	rockchip->aclk_rst = devm_reset_control_get_exclusive(dev, "aclk");
    114	if (IS_ERR(rockchip->aclk_rst)) {
    115		if (PTR_ERR(rockchip->aclk_rst) != -EPROBE_DEFER)
    116			dev_err(dev, "missing aclk reset property in node\n");
    117		return PTR_ERR(rockchip->aclk_rst);
    118	}
    119
    120	if (rockchip->is_rc) {
    121		rockchip->ep_gpio = devm_gpiod_get_optional(dev, "ep",
    122							    GPIOD_OUT_HIGH);
    123		if (IS_ERR(rockchip->ep_gpio))
    124			return dev_err_probe(dev, PTR_ERR(rockchip->ep_gpio),
    125					     "failed to get ep GPIO\n");
    126	}
    127
    128	rockchip->aclk_pcie = devm_clk_get(dev, "aclk");
    129	if (IS_ERR(rockchip->aclk_pcie)) {
    130		dev_err(dev, "aclk clock not found\n");
    131		return PTR_ERR(rockchip->aclk_pcie);
    132	}
    133
    134	rockchip->aclk_perf_pcie = devm_clk_get(dev, "aclk-perf");
    135	if (IS_ERR(rockchip->aclk_perf_pcie)) {
    136		dev_err(dev, "aclk_perf clock not found\n");
    137		return PTR_ERR(rockchip->aclk_perf_pcie);
    138	}
    139
    140	rockchip->hclk_pcie = devm_clk_get(dev, "hclk");
    141	if (IS_ERR(rockchip->hclk_pcie)) {
    142		dev_err(dev, "hclk clock not found\n");
    143		return PTR_ERR(rockchip->hclk_pcie);
    144	}
    145
    146	rockchip->clk_pcie_pm = devm_clk_get(dev, "pm");
    147	if (IS_ERR(rockchip->clk_pcie_pm)) {
    148		dev_err(dev, "pm clock not found\n");
    149		return PTR_ERR(rockchip->clk_pcie_pm);
    150	}
    151
    152	return 0;
    153}
    154EXPORT_SYMBOL_GPL(rockchip_pcie_parse_dt);
    155
    156int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
    157{
    158	struct device *dev = rockchip->dev;
    159	int err, i;
    160	u32 regs;
    161
    162	err = reset_control_assert(rockchip->aclk_rst);
    163	if (err) {
    164		dev_err(dev, "assert aclk_rst err %d\n", err);
    165		return err;
    166	}
    167
    168	err = reset_control_assert(rockchip->pclk_rst);
    169	if (err) {
    170		dev_err(dev, "assert pclk_rst err %d\n", err);
    171		return err;
    172	}
    173
    174	err = reset_control_assert(rockchip->pm_rst);
    175	if (err) {
    176		dev_err(dev, "assert pm_rst err %d\n", err);
    177		return err;
    178	}
    179
    180	for (i = 0; i < MAX_LANE_NUM; i++) {
    181		err = phy_init(rockchip->phys[i]);
    182		if (err) {
    183			dev_err(dev, "init phy%d err %d\n", i, err);
    184			goto err_exit_phy;
    185		}
    186	}
    187
    188	err = reset_control_assert(rockchip->core_rst);
    189	if (err) {
    190		dev_err(dev, "assert core_rst err %d\n", err);
    191		goto err_exit_phy;
    192	}
    193
    194	err = reset_control_assert(rockchip->mgmt_rst);
    195	if (err) {
    196		dev_err(dev, "assert mgmt_rst err %d\n", err);
    197		goto err_exit_phy;
    198	}
    199
    200	err = reset_control_assert(rockchip->mgmt_sticky_rst);
    201	if (err) {
    202		dev_err(dev, "assert mgmt_sticky_rst err %d\n", err);
    203		goto err_exit_phy;
    204	}
    205
    206	err = reset_control_assert(rockchip->pipe_rst);
    207	if (err) {
    208		dev_err(dev, "assert pipe_rst err %d\n", err);
    209		goto err_exit_phy;
    210	}
    211
    212	udelay(10);
    213
    214	err = reset_control_deassert(rockchip->pm_rst);
    215	if (err) {
    216		dev_err(dev, "deassert pm_rst err %d\n", err);
    217		goto err_exit_phy;
    218	}
    219
    220	err = reset_control_deassert(rockchip->aclk_rst);
    221	if (err) {
    222		dev_err(dev, "deassert aclk_rst err %d\n", err);
    223		goto err_exit_phy;
    224	}
    225
    226	err = reset_control_deassert(rockchip->pclk_rst);
    227	if (err) {
    228		dev_err(dev, "deassert pclk_rst err %d\n", err);
    229		goto err_exit_phy;
    230	}
    231
    232	if (rockchip->link_gen == 2)
    233		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
    234				    PCIE_CLIENT_CONFIG);
    235	else
    236		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
    237				    PCIE_CLIENT_CONFIG);
    238
    239	regs = PCIE_CLIENT_LINK_TRAIN_ENABLE | PCIE_CLIENT_ARI_ENABLE |
    240	       PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes);
    241
    242	if (rockchip->is_rc)
    243		regs |= PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_MODE_RC;
    244	else
    245		regs |= PCIE_CLIENT_CONF_DISABLE | PCIE_CLIENT_MODE_EP;
    246
    247	rockchip_pcie_write(rockchip, regs, PCIE_CLIENT_CONFIG);
    248
    249	for (i = 0; i < MAX_LANE_NUM; i++) {
    250		err = phy_power_on(rockchip->phys[i]);
    251		if (err) {
    252			dev_err(dev, "power on phy%d err %d\n", i, err);
    253			goto err_power_off_phy;
    254		}
    255	}
    256
    257	/*
    258	 * Please don't reorder the deassert sequence of the following
    259	 * four reset pins.
    260	 */
    261	err = reset_control_deassert(rockchip->mgmt_sticky_rst);
    262	if (err) {
    263		dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err);
    264		goto err_power_off_phy;
    265	}
    266
    267	err = reset_control_deassert(rockchip->core_rst);
    268	if (err) {
    269		dev_err(dev, "deassert core_rst err %d\n", err);
    270		goto err_power_off_phy;
    271	}
    272
    273	err = reset_control_deassert(rockchip->mgmt_rst);
    274	if (err) {
    275		dev_err(dev, "deassert mgmt_rst err %d\n", err);
    276		goto err_power_off_phy;
    277	}
    278
    279	err = reset_control_deassert(rockchip->pipe_rst);
    280	if (err) {
    281		dev_err(dev, "deassert pipe_rst err %d\n", err);
    282		goto err_power_off_phy;
    283	}
    284
    285	return 0;
    286err_power_off_phy:
    287	while (i--)
    288		phy_power_off(rockchip->phys[i]);
    289	i = MAX_LANE_NUM;
    290err_exit_phy:
    291	while (i--)
    292		phy_exit(rockchip->phys[i]);
    293	return err;
    294}
    295EXPORT_SYMBOL_GPL(rockchip_pcie_init_port);
    296
    297int rockchip_pcie_get_phys(struct rockchip_pcie *rockchip)
    298{
    299	struct device *dev = rockchip->dev;
    300	struct phy *phy;
    301	char *name;
    302	u32 i;
    303
    304	phy = devm_phy_get(dev, "pcie-phy");
    305	if (!IS_ERR(phy)) {
    306		rockchip->legacy_phy = true;
    307		rockchip->phys[0] = phy;
    308		dev_warn(dev, "legacy phy model is deprecated!\n");
    309		return 0;
    310	}
    311
    312	if (PTR_ERR(phy) == -EPROBE_DEFER)
    313		return PTR_ERR(phy);
    314
    315	dev_dbg(dev, "missing legacy phy; search for per-lane PHY\n");
    316
    317	for (i = 0; i < MAX_LANE_NUM; i++) {
    318		name = kasprintf(GFP_KERNEL, "pcie-phy-%u", i);
    319		if (!name)
    320			return -ENOMEM;
    321
    322		phy = devm_of_phy_get(dev, dev->of_node, name);
    323		kfree(name);
    324
    325		if (IS_ERR(phy)) {
    326			if (PTR_ERR(phy) != -EPROBE_DEFER)
    327				dev_err(dev, "missing phy for lane %d: %ld\n",
    328					i, PTR_ERR(phy));
    329			return PTR_ERR(phy);
    330		}
    331
    332		rockchip->phys[i] = phy;
    333	}
    334
    335	return 0;
    336}
    337EXPORT_SYMBOL_GPL(rockchip_pcie_get_phys);
    338
    339void rockchip_pcie_deinit_phys(struct rockchip_pcie *rockchip)
    340{
    341	int i;
    342
    343	for (i = 0; i < MAX_LANE_NUM; i++) {
    344		/* inactive lanes are already powered off */
    345		if (rockchip->lanes_map & BIT(i))
    346			phy_power_off(rockchip->phys[i]);
    347		phy_exit(rockchip->phys[i]);
    348	}
    349}
    350EXPORT_SYMBOL_GPL(rockchip_pcie_deinit_phys);
    351
    352int rockchip_pcie_enable_clocks(struct rockchip_pcie *rockchip)
    353{
    354	struct device *dev = rockchip->dev;
    355	int err;
    356
    357	err = clk_prepare_enable(rockchip->aclk_pcie);
    358	if (err) {
    359		dev_err(dev, "unable to enable aclk_pcie clock\n");
    360		return err;
    361	}
    362
    363	err = clk_prepare_enable(rockchip->aclk_perf_pcie);
    364	if (err) {
    365		dev_err(dev, "unable to enable aclk_perf_pcie clock\n");
    366		goto err_aclk_perf_pcie;
    367	}
    368
    369	err = clk_prepare_enable(rockchip->hclk_pcie);
    370	if (err) {
    371		dev_err(dev, "unable to enable hclk_pcie clock\n");
    372		goto err_hclk_pcie;
    373	}
    374
    375	err = clk_prepare_enable(rockchip->clk_pcie_pm);
    376	if (err) {
    377		dev_err(dev, "unable to enable clk_pcie_pm clock\n");
    378		goto err_clk_pcie_pm;
    379	}
    380
    381	return 0;
    382
    383err_clk_pcie_pm:
    384	clk_disable_unprepare(rockchip->hclk_pcie);
    385err_hclk_pcie:
    386	clk_disable_unprepare(rockchip->aclk_perf_pcie);
    387err_aclk_perf_pcie:
    388	clk_disable_unprepare(rockchip->aclk_pcie);
    389	return err;
    390}
    391EXPORT_SYMBOL_GPL(rockchip_pcie_enable_clocks);
    392
    393void rockchip_pcie_disable_clocks(void *data)
    394{
    395	struct rockchip_pcie *rockchip = data;
    396
    397	clk_disable_unprepare(rockchip->clk_pcie_pm);
    398	clk_disable_unprepare(rockchip->hclk_pcie);
    399	clk_disable_unprepare(rockchip->aclk_perf_pcie);
    400	clk_disable_unprepare(rockchip->aclk_pcie);
    401}
    402EXPORT_SYMBOL_GPL(rockchip_pcie_disable_clocks);
    403
    404void rockchip_pcie_cfg_configuration_accesses(
    405		struct rockchip_pcie *rockchip, u32 type)
    406{
    407	u32 ob_desc_0;
    408
    409	/* Configuration Accesses for region 0 */
    410	rockchip_pcie_write(rockchip, 0x0, PCIE_RC_BAR_CONF);
    411
    412	rockchip_pcie_write(rockchip,
    413			    (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS),
    414			    PCIE_CORE_OB_REGION_ADDR0);
    415	rockchip_pcie_write(rockchip, RC_REGION_0_ADDR_TRANS_H,
    416			    PCIE_CORE_OB_REGION_ADDR1);
    417	ob_desc_0 = rockchip_pcie_read(rockchip, PCIE_CORE_OB_REGION_DESC0);
    418	ob_desc_0 &= ~(RC_REGION_0_TYPE_MASK);
    419	ob_desc_0 |= (type | (0x1 << 23));
    420	rockchip_pcie_write(rockchip, ob_desc_0, PCIE_CORE_OB_REGION_DESC0);
    421	rockchip_pcie_write(rockchip, 0x0, PCIE_CORE_OB_REGION_DESC1);
    422}
    423EXPORT_SYMBOL_GPL(rockchip_pcie_cfg_configuration_accesses);