162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCIe controller EP driver for Freescale Layerscape SoCs
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2018 NXP Semiconductor.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Xiaowei Bao <xiaowei.bao@nxp.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/of_pci.h>
1362306a36Sopenharmony_ci#include <linux/of_platform.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci#include <linux/pci.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/resource.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "pcie-designware.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define PEX_PF0_CONFIG			0xC0014
2262306a36Sopenharmony_ci#define PEX_PF0_CFG_READY		BIT(0)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* PEX PFa PCIE PME and message interrupt registers*/
2562306a36Sopenharmony_ci#define PEX_PF0_PME_MES_DR		0xC0020
2662306a36Sopenharmony_ci#define PEX_PF0_PME_MES_DR_LUD		BIT(7)
2762306a36Sopenharmony_ci#define PEX_PF0_PME_MES_DR_LDD		BIT(9)
2862306a36Sopenharmony_ci#define PEX_PF0_PME_MES_DR_HRD		BIT(10)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define PEX_PF0_PME_MES_IER		0xC0028
3162306a36Sopenharmony_ci#define PEX_PF0_PME_MES_IER_LUDIE	BIT(7)
3262306a36Sopenharmony_ci#define PEX_PF0_PME_MES_IER_LDDIE	BIT(9)
3362306a36Sopenharmony_ci#define PEX_PF0_PME_MES_IER_HRDIE	BIT(10)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define to_ls_pcie_ep(x)	dev_get_drvdata((x)->dev)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistruct ls_pcie_ep_drvdata {
3862306a36Sopenharmony_ci	u32				func_offset;
3962306a36Sopenharmony_ci	const struct dw_pcie_ep_ops	*ops;
4062306a36Sopenharmony_ci	const struct dw_pcie_ops	*dw_pcie_ops;
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct ls_pcie_ep {
4462306a36Sopenharmony_ci	struct dw_pcie			*pci;
4562306a36Sopenharmony_ci	struct pci_epc_features		*ls_epc;
4662306a36Sopenharmony_ci	const struct ls_pcie_ep_drvdata *drvdata;
4762306a36Sopenharmony_ci	int				irq;
4862306a36Sopenharmony_ci	u32				lnkcap;
4962306a36Sopenharmony_ci	bool				big_endian;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct dw_pcie *pci = pcie->pci;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (pcie->big_endian)
5762306a36Sopenharmony_ci		return ioread32be(pci->dbi_base + offset);
5862306a36Sopenharmony_ci	else
5962306a36Sopenharmony_ci		return ioread32(pci->dbi_base + offset);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct dw_pcie *pci = pcie->pci;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (pcie->big_endian)
6762306a36Sopenharmony_ci		iowrite32be(value, pci->dbi_base + offset);
6862306a36Sopenharmony_ci	else
6962306a36Sopenharmony_ci		iowrite32(value, pci->dbi_base + offset);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct ls_pcie_ep *pcie = dev_id;
7562306a36Sopenharmony_ci	struct dw_pcie *pci = pcie->pci;
7662306a36Sopenharmony_ci	u32 val, cfg;
7762306a36Sopenharmony_ci	u8 offset;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
8062306a36Sopenharmony_ci	ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (!val)
8362306a36Sopenharmony_ci		return IRQ_NONE;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (val & PEX_PF0_PME_MES_DR_LUD) {
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		/*
9062306a36Sopenharmony_ci		 * The values of the Maximum Link Width and Supported Link
9162306a36Sopenharmony_ci		 * Speed from the Link Capabilities Register will be lost
9262306a36Sopenharmony_ci		 * during link down or hot reset. Restore initial value
9362306a36Sopenharmony_ci		 * that configured by the Reset Configuration Word (RCW).
9462306a36Sopenharmony_ci		 */
9562306a36Sopenharmony_ci		dw_pcie_dbi_ro_wr_en(pci);
9662306a36Sopenharmony_ci		dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, pcie->lnkcap);
9762306a36Sopenharmony_ci		dw_pcie_dbi_ro_wr_dis(pci);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		cfg = ls_lut_readl(pcie, PEX_PF0_CONFIG);
10062306a36Sopenharmony_ci		cfg |= PEX_PF0_CFG_READY;
10162306a36Sopenharmony_ci		ls_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
10262306a36Sopenharmony_ci		dw_pcie_ep_linkup(&pci->ep);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		dev_dbg(pci->dev, "Link up\n");
10562306a36Sopenharmony_ci	} else if (val & PEX_PF0_PME_MES_DR_LDD) {
10662306a36Sopenharmony_ci		dev_dbg(pci->dev, "Link down\n");
10762306a36Sopenharmony_ci		pci_epc_linkdown(pci->ep.epc);
10862306a36Sopenharmony_ci	} else if (val & PEX_PF0_PME_MES_DR_HRD) {
10962306a36Sopenharmony_ci		dev_dbg(pci->dev, "Hot reset\n");
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return IRQ_HANDLED;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
11662306a36Sopenharmony_ci				     struct platform_device *pdev)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	u32 val;
11962306a36Sopenharmony_ci	int ret;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	pcie->irq = platform_get_irq_byname(pdev, "pme");
12262306a36Sopenharmony_ci	if (pcie->irq < 0)
12362306a36Sopenharmony_ci		return pcie->irq;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, pcie->irq, ls_pcie_ep_event_handler,
12662306a36Sopenharmony_ci			       IRQF_SHARED, pdev->name, pcie);
12762306a36Sopenharmony_ci	if (ret) {
12862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Can't register PCIe IRQ\n");
12962306a36Sopenharmony_ci		return ret;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Enable interrupts */
13362306a36Sopenharmony_ci	val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
13462306a36Sopenharmony_ci	val |=  PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
13562306a36Sopenharmony_ci		PEX_PF0_PME_MES_IER_LUDIE;
13662306a36Sopenharmony_ci	ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic const struct pci_epc_features*
14262306a36Sopenharmony_cils_pcie_ep_get_features(struct dw_pcie_ep *ep)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
14562306a36Sopenharmony_ci	struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return pcie->ls_epc;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void ls_pcie_ep_init(struct dw_pcie_ep *ep)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
15362306a36Sopenharmony_ci	struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
15462306a36Sopenharmony_ci	struct dw_pcie_ep_func *ep_func;
15562306a36Sopenharmony_ci	enum pci_barno bar;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	ep_func = dw_pcie_ep_get_func_from_ep(ep, 0);
15862306a36Sopenharmony_ci	if (!ep_func)
15962306a36Sopenharmony_ci		return;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
16262306a36Sopenharmony_ci		dw_pcie_ep_reset_bar(pci, bar);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false;
16562306a36Sopenharmony_ci	pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
16962306a36Sopenharmony_ci				enum pci_epc_irq_type type, u16 interrupt_num)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	switch (type) {
17462306a36Sopenharmony_ci	case PCI_EPC_IRQ_LEGACY:
17562306a36Sopenharmony_ci		return dw_pcie_ep_raise_legacy_irq(ep, func_no);
17662306a36Sopenharmony_ci	case PCI_EPC_IRQ_MSI:
17762306a36Sopenharmony_ci		return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
17862306a36Sopenharmony_ci	case PCI_EPC_IRQ_MSIX:
17962306a36Sopenharmony_ci		return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no,
18062306a36Sopenharmony_ci							  interrupt_num);
18162306a36Sopenharmony_ci	default:
18262306a36Sopenharmony_ci		dev_err(pci->dev, "UNKNOWN IRQ type\n");
18362306a36Sopenharmony_ci		return -EINVAL;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
18862306a36Sopenharmony_ci						u8 func_no)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
19162306a36Sopenharmony_ci	struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	WARN_ON(func_no && !pcie->drvdata->func_offset);
19462306a36Sopenharmony_ci	return pcie->drvdata->func_offset * func_no;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic const struct dw_pcie_ep_ops ls_pcie_ep_ops = {
19862306a36Sopenharmony_ci	.ep_init = ls_pcie_ep_init,
19962306a36Sopenharmony_ci	.raise_irq = ls_pcie_ep_raise_irq,
20062306a36Sopenharmony_ci	.get_features = ls_pcie_ep_get_features,
20162306a36Sopenharmony_ci	.func_conf_select = ls_pcie_ep_func_conf_select,
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic const struct ls_pcie_ep_drvdata ls1_ep_drvdata = {
20562306a36Sopenharmony_ci	.ops = &ls_pcie_ep_ops,
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic const struct ls_pcie_ep_drvdata ls2_ep_drvdata = {
20962306a36Sopenharmony_ci	.func_offset = 0x20000,
21062306a36Sopenharmony_ci	.ops = &ls_pcie_ep_ops,
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic const struct ls_pcie_ep_drvdata lx2_ep_drvdata = {
21462306a36Sopenharmony_ci	.func_offset = 0x8000,
21562306a36Sopenharmony_ci	.ops = &ls_pcie_ep_ops,
21662306a36Sopenharmony_ci};
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic const struct of_device_id ls_pcie_ep_of_match[] = {
21962306a36Sopenharmony_ci	{ .compatible = "fsl,ls1028a-pcie-ep", .data = &ls1_ep_drvdata },
22062306a36Sopenharmony_ci	{ .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata },
22162306a36Sopenharmony_ci	{ .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata },
22262306a36Sopenharmony_ci	{ .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata },
22362306a36Sopenharmony_ci	{ .compatible = "fsl,lx2160ar2-pcie-ep", .data = &lx2_ep_drvdata },
22462306a36Sopenharmony_ci	{ },
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic int __init ls_pcie_ep_probe(struct platform_device *pdev)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
23062306a36Sopenharmony_ci	struct dw_pcie *pci;
23162306a36Sopenharmony_ci	struct ls_pcie_ep *pcie;
23262306a36Sopenharmony_ci	struct pci_epc_features *ls_epc;
23362306a36Sopenharmony_ci	struct resource *dbi_base;
23462306a36Sopenharmony_ci	u8 offset;
23562306a36Sopenharmony_ci	int ret;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
23862306a36Sopenharmony_ci	if (!pcie)
23962306a36Sopenharmony_ci		return -ENOMEM;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
24262306a36Sopenharmony_ci	if (!pci)
24362306a36Sopenharmony_ci		return -ENOMEM;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL);
24662306a36Sopenharmony_ci	if (!ls_epc)
24762306a36Sopenharmony_ci		return -ENOMEM;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	pcie->drvdata = of_device_get_match_data(dev);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	pci->dev = dev;
25262306a36Sopenharmony_ci	pci->ops = pcie->drvdata->dw_pcie_ops;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4);
25562306a36Sopenharmony_ci	ls_epc->linkup_notifier = true;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	pcie->pci = pci;
25862306a36Sopenharmony_ci	pcie->ls_epc = ls_epc;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
26162306a36Sopenharmony_ci	pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
26262306a36Sopenharmony_ci	if (IS_ERR(pci->dbi_base))
26362306a36Sopenharmony_ci		return PTR_ERR(pci->dbi_base);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	pci->ep.ops = &ls_pcie_ep_ops;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	platform_set_drvdata(pdev, pcie);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
27262306a36Sopenharmony_ci	pcie->lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	ret = dw_pcie_ep_init(&pci->ep);
27562306a36Sopenharmony_ci	if (ret)
27662306a36Sopenharmony_ci		return ret;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return ls_pcie_ep_interrupt_init(pcie, pdev);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic struct platform_driver ls_pcie_ep_driver = {
28262306a36Sopenharmony_ci	.driver = {
28362306a36Sopenharmony_ci		.name = "layerscape-pcie-ep",
28462306a36Sopenharmony_ci		.of_match_table = ls_pcie_ep_of_match,
28562306a36Sopenharmony_ci		.suppress_bind_attrs = true,
28662306a36Sopenharmony_ci	},
28762306a36Sopenharmony_ci};
28862306a36Sopenharmony_cibuiltin_platform_driver_probe(ls_pcie_ep_driver, ls_pcie_ep_probe);
289