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

pci-exynos.c (11029B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * PCIe host controller driver for Samsung Exynos SoCs
      4 *
      5 * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd.
      6 *		https://www.samsung.com
      7 *
      8 * Author: Jingoo Han <jg1.han@samsung.com>
      9 *	   Jaehoon Chung <jh80.chung@samsung.com>
     10 */
     11
     12#include <linux/clk.h>
     13#include <linux/delay.h>
     14#include <linux/interrupt.h>
     15#include <linux/kernel.h>
     16#include <linux/init.h>
     17#include <linux/of_device.h>
     18#include <linux/pci.h>
     19#include <linux/platform_device.h>
     20#include <linux/phy/phy.h>
     21#include <linux/regulator/consumer.h>
     22#include <linux/module.h>
     23
     24#include "pcie-designware.h"
     25
     26#define to_exynos_pcie(x)	dev_get_drvdata((x)->dev)
     27
     28/* PCIe ELBI registers */
     29#define PCIE_IRQ_PULSE			0x000
     30#define IRQ_INTA_ASSERT			BIT(0)
     31#define IRQ_INTB_ASSERT			BIT(2)
     32#define IRQ_INTC_ASSERT			BIT(4)
     33#define IRQ_INTD_ASSERT			BIT(6)
     34#define PCIE_IRQ_LEVEL			0x004
     35#define PCIE_IRQ_SPECIAL		0x008
     36#define PCIE_IRQ_EN_PULSE		0x00c
     37#define PCIE_IRQ_EN_LEVEL		0x010
     38#define PCIE_IRQ_EN_SPECIAL		0x014
     39#define PCIE_SW_WAKE			0x018
     40#define PCIE_BUS_EN			BIT(1)
     41#define PCIE_CORE_RESET			0x01c
     42#define PCIE_CORE_RESET_ENABLE		BIT(0)
     43#define PCIE_STICKY_RESET		0x020
     44#define PCIE_NONSTICKY_RESET		0x024
     45#define PCIE_APP_INIT_RESET		0x028
     46#define PCIE_APP_LTSSM_ENABLE		0x02c
     47#define PCIE_ELBI_RDLH_LINKUP		0x074
     48#define PCIE_ELBI_XMLH_LINKUP		BIT(4)
     49#define PCIE_ELBI_LTSSM_ENABLE		0x1
     50#define PCIE_ELBI_SLV_AWMISC		0x11c
     51#define PCIE_ELBI_SLV_ARMISC		0x120
     52#define PCIE_ELBI_SLV_DBI_ENABLE	BIT(21)
     53
     54struct exynos_pcie {
     55	struct dw_pcie			pci;
     56	void __iomem			*elbi_base;
     57	struct clk			*clk;
     58	struct clk			*bus_clk;
     59	struct phy			*phy;
     60	struct regulator_bulk_data	supplies[2];
     61};
     62
     63static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep)
     64{
     65	struct device *dev = ep->pci.dev;
     66	int ret;
     67
     68	ret = clk_prepare_enable(ep->clk);
     69	if (ret) {
     70		dev_err(dev, "cannot enable pcie rc clock");
     71		return ret;
     72	}
     73
     74	ret = clk_prepare_enable(ep->bus_clk);
     75	if (ret) {
     76		dev_err(dev, "cannot enable pcie bus clock");
     77		goto err_bus_clk;
     78	}
     79
     80	return 0;
     81
     82err_bus_clk:
     83	clk_disable_unprepare(ep->clk);
     84
     85	return ret;
     86}
     87
     88static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep)
     89{
     90	clk_disable_unprepare(ep->bus_clk);
     91	clk_disable_unprepare(ep->clk);
     92}
     93
     94static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
     95{
     96	writel(val, base + reg);
     97}
     98
     99static u32 exynos_pcie_readl(void __iomem *base, u32 reg)
    100{
    101	return readl(base + reg);
    102}
    103
    104static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
    105{
    106	u32 val;
    107
    108	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
    109	if (on)
    110		val |= PCIE_ELBI_SLV_DBI_ENABLE;
    111	else
    112		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
    113	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
    114}
    115
    116static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
    117{
    118	u32 val;
    119
    120	val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
    121	if (on)
    122		val |= PCIE_ELBI_SLV_DBI_ENABLE;
    123	else
    124		val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
    125	exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
    126}
    127
    128static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
    129{
    130	u32 val;
    131
    132	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
    133	val &= ~PCIE_CORE_RESET_ENABLE;
    134	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
    135	exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
    136	exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
    137}
    138
    139static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
    140{
    141	u32 val;
    142
    143	val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
    144	val |= PCIE_CORE_RESET_ENABLE;
    145
    146	exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
    147	exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
    148	exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
    149	exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
    150	exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
    151}
    152
    153static int exynos_pcie_start_link(struct dw_pcie *pci)
    154{
    155	struct exynos_pcie *ep = to_exynos_pcie(pci);
    156	u32 val;
    157
    158	val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE);
    159	val &= ~PCIE_BUS_EN;
    160	exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE);
    161
    162	/* assert LTSSM enable */
    163	exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
    164			  PCIE_APP_LTSSM_ENABLE);
    165	return 0;
    166}
    167
    168static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
    169{
    170	u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
    171
    172	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
    173}
    174
    175static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
    176{
    177	struct exynos_pcie *ep = arg;
    178
    179	exynos_pcie_clear_irq_pulse(ep);
    180	return IRQ_HANDLED;
    181}
    182
    183static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
    184{
    185	u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
    186		  IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
    187
    188	exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
    189	exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL);
    190	exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL);
    191}
    192
    193static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
    194				u32 reg, size_t size)
    195{
    196	struct exynos_pcie *ep = to_exynos_pcie(pci);
    197	u32 val;
    198
    199	exynos_pcie_sideband_dbi_r_mode(ep, true);
    200	dw_pcie_read(base + reg, size, &val);
    201	exynos_pcie_sideband_dbi_r_mode(ep, false);
    202	return val;
    203}
    204
    205static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
    206				  u32 reg, size_t size, u32 val)
    207{
    208	struct exynos_pcie *ep = to_exynos_pcie(pci);
    209
    210	exynos_pcie_sideband_dbi_w_mode(ep, true);
    211	dw_pcie_write(base + reg, size, val);
    212	exynos_pcie_sideband_dbi_w_mode(ep, false);
    213}
    214
    215static int exynos_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
    216				   int where, int size, u32 *val)
    217{
    218	struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
    219
    220	if (PCI_SLOT(devfn))
    221		return PCIBIOS_DEVICE_NOT_FOUND;
    222
    223	*val = dw_pcie_read_dbi(pci, where, size);
    224	return PCIBIOS_SUCCESSFUL;
    225}
    226
    227static int exynos_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
    228				   int where, int size, u32 val)
    229{
    230	struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
    231
    232	if (PCI_SLOT(devfn))
    233		return PCIBIOS_DEVICE_NOT_FOUND;
    234
    235	dw_pcie_write_dbi(pci, where, size, val);
    236	return PCIBIOS_SUCCESSFUL;
    237}
    238
    239static struct pci_ops exynos_pci_ops = {
    240	.read = exynos_pcie_rd_own_conf,
    241	.write = exynos_pcie_wr_own_conf,
    242};
    243
    244static int exynos_pcie_link_up(struct dw_pcie *pci)
    245{
    246	struct exynos_pcie *ep = to_exynos_pcie(pci);
    247	u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP);
    248
    249	return (val & PCIE_ELBI_XMLH_LINKUP);
    250}
    251
    252static int exynos_pcie_host_init(struct pcie_port *pp)
    253{
    254	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
    255	struct exynos_pcie *ep = to_exynos_pcie(pci);
    256
    257	pp->bridge->ops = &exynos_pci_ops;
    258
    259	exynos_pcie_assert_core_reset(ep);
    260
    261	phy_reset(ep->phy);
    262	phy_power_on(ep->phy);
    263	phy_init(ep->phy);
    264
    265	exynos_pcie_deassert_core_reset(ep);
    266	exynos_pcie_enable_irq_pulse(ep);
    267
    268	return 0;
    269}
    270
    271static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
    272	.host_init = exynos_pcie_host_init,
    273};
    274
    275static int exynos_add_pcie_port(struct exynos_pcie *ep,
    276				       struct platform_device *pdev)
    277{
    278	struct dw_pcie *pci = &ep->pci;
    279	struct pcie_port *pp = &pci->pp;
    280	struct device *dev = &pdev->dev;
    281	int ret;
    282
    283	pp->irq = platform_get_irq(pdev, 0);
    284	if (pp->irq < 0)
    285		return pp->irq;
    286
    287	ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler,
    288			       IRQF_SHARED, "exynos-pcie", ep);
    289	if (ret) {
    290		dev_err(dev, "failed to request irq\n");
    291		return ret;
    292	}
    293
    294	pp->ops = &exynos_pcie_host_ops;
    295	pp->msi_irq = -ENODEV;
    296
    297	ret = dw_pcie_host_init(pp);
    298	if (ret) {
    299		dev_err(dev, "failed to initialize host\n");
    300		return ret;
    301	}
    302
    303	return 0;
    304}
    305
    306static const struct dw_pcie_ops dw_pcie_ops = {
    307	.read_dbi = exynos_pcie_read_dbi,
    308	.write_dbi = exynos_pcie_write_dbi,
    309	.link_up = exynos_pcie_link_up,
    310	.start_link = exynos_pcie_start_link,
    311};
    312
    313static int exynos_pcie_probe(struct platform_device *pdev)
    314{
    315	struct device *dev = &pdev->dev;
    316	struct exynos_pcie *ep;
    317	struct device_node *np = dev->of_node;
    318	int ret;
    319
    320	ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
    321	if (!ep)
    322		return -ENOMEM;
    323
    324	ep->pci.dev = dev;
    325	ep->pci.ops = &dw_pcie_ops;
    326
    327	ep->phy = devm_of_phy_get(dev, np, NULL);
    328	if (IS_ERR(ep->phy))
    329		return PTR_ERR(ep->phy);
    330
    331	/* External Local Bus interface (ELBI) registers */
    332	ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
    333	if (IS_ERR(ep->elbi_base))
    334		return PTR_ERR(ep->elbi_base);
    335
    336	ep->clk = devm_clk_get(dev, "pcie");
    337	if (IS_ERR(ep->clk)) {
    338		dev_err(dev, "Failed to get pcie rc clock\n");
    339		return PTR_ERR(ep->clk);
    340	}
    341
    342	ep->bus_clk = devm_clk_get(dev, "pcie_bus");
    343	if (IS_ERR(ep->bus_clk)) {
    344		dev_err(dev, "Failed to get pcie bus clock\n");
    345		return PTR_ERR(ep->bus_clk);
    346	}
    347
    348	ep->supplies[0].supply = "vdd18";
    349	ep->supplies[1].supply = "vdd10";
    350	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies),
    351				      ep->supplies);
    352	if (ret)
    353		return ret;
    354
    355	ret = exynos_pcie_init_clk_resources(ep);
    356	if (ret)
    357		return ret;
    358
    359	ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
    360	if (ret)
    361		return ret;
    362
    363	platform_set_drvdata(pdev, ep);
    364
    365	ret = exynos_add_pcie_port(ep, pdev);
    366	if (ret < 0)
    367		goto fail_probe;
    368
    369	return 0;
    370
    371fail_probe:
    372	phy_exit(ep->phy);
    373	exynos_pcie_deinit_clk_resources(ep);
    374	regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
    375
    376	return ret;
    377}
    378
    379static int __exit exynos_pcie_remove(struct platform_device *pdev)
    380{
    381	struct exynos_pcie *ep = platform_get_drvdata(pdev);
    382
    383	dw_pcie_host_deinit(&ep->pci.pp);
    384	exynos_pcie_assert_core_reset(ep);
    385	phy_power_off(ep->phy);
    386	phy_exit(ep->phy);
    387	exynos_pcie_deinit_clk_resources(ep);
    388	regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
    389
    390	return 0;
    391}
    392
    393static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev)
    394{
    395	struct exynos_pcie *ep = dev_get_drvdata(dev);
    396
    397	exynos_pcie_assert_core_reset(ep);
    398	phy_power_off(ep->phy);
    399	phy_exit(ep->phy);
    400	regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
    401
    402	return 0;
    403}
    404
    405static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev)
    406{
    407	struct exynos_pcie *ep = dev_get_drvdata(dev);
    408	struct dw_pcie *pci = &ep->pci;
    409	struct pcie_port *pp = &pci->pp;
    410	int ret;
    411
    412	ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
    413	if (ret)
    414		return ret;
    415
    416	/* exynos_pcie_host_init controls ep->phy */
    417	exynos_pcie_host_init(pp);
    418	dw_pcie_setup_rc(pp);
    419	exynos_pcie_start_link(pci);
    420	return dw_pcie_wait_for_link(pci);
    421}
    422
    423static const struct dev_pm_ops exynos_pcie_pm_ops = {
    424	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq,
    425				      exynos_pcie_resume_noirq)
    426};
    427
    428static const struct of_device_id exynos_pcie_of_match[] = {
    429	{ .compatible = "samsung,exynos5433-pcie", },
    430	{ },
    431};
    432
    433static struct platform_driver exynos_pcie_driver = {
    434	.probe		= exynos_pcie_probe,
    435	.remove		= __exit_p(exynos_pcie_remove),
    436	.driver = {
    437		.name	= "exynos-pcie",
    438		.of_match_table = exynos_pcie_of_match,
    439		.pm		= &exynos_pcie_pm_ops,
    440	},
    441};
    442module_platform_driver(exynos_pcie_driver);
    443MODULE_LICENSE("GPL v2");
    444MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);