blob: 6a4f0619bb1cd8283441816e6c13e4cf1ea28928 [file] [log] [blame]
Bjorn Helgaas8cfab3c2018-01-26 12:50:27 -06001// SPDX-License-Identifier: GPL-2.0
Minghuan Lian62d0ff832014-11-05 16:45:11 +08002/*
3 * PCIe host controller driver for Freescale Layerscape SoCs
4 *
5 * Copyright (C) 2014 Freescale Semiconductor.
Hou Zhiqiangd23f0c12021-12-24 17:40:00 +08006 * Copyright 2021 NXP
Minghuan Lian62d0ff832014-11-05 16:45:11 +08007 *
Minghuan Lian5192ec72015-10-16 15:19:19 +08008 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
Minghuan Lian62d0ff832014-11-05 16:45:11 +08009 */
10
11#include <linux/kernel.h>
Minghuan Lian62d0ff832014-11-05 16:45:11 +080012#include <linux/interrupt.h>
Paul Gortmaker154fb602016-07-02 19:13:27 -040013#include <linux/init.h>
Minghuan Lian62d0ff832014-11-05 16:45:11 +080014#include <linux/of_pci.h>
15#include <linux/of_platform.h>
16#include <linux/of_irq.h>
17#include <linux/of_address.h>
18#include <linux/pci.h>
19#include <linux/platform_device.h>
20#include <linux/resource.h>
21#include <linux/mfd/syscon.h>
22#include <linux/regmap.h>
23
24#include "pcie-designware.h"
25
Minghuan Lian5192ec72015-10-16 15:19:19 +080026/* PEX Internal Configuration Registers */
27#define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */
Minghuan Lian84d897d2017-10-12 17:44:48 +080028#define PCIE_ABSERR 0x8d0 /* Bridge Slave Error Response Register */
29#define PCIE_ABSERR_SETTING 0x9401 /* Forward error of non-posted request */
Minghuan Lian5192ec72015-10-16 15:19:19 +080030
Hou Zhiqiang4a2745d2017-08-28 18:52:58 +080031#define PCIE_IATU_NUM 6
32
Minghuan Lian62d0ff832014-11-05 16:45:11 +080033struct ls_pcie {
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053034 struct dw_pcie *pci;
Minghuan Lian62d0ff832014-11-05 16:45:11 +080035};
36
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053037#define to_ls_pcie(x) dev_get_drvdata((x)->dev)
Minghuan Lian62d0ff832014-11-05 16:45:11 +080038
Minghuan Lian7af4ce32015-10-16 15:19:16 +080039static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
40{
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053041 struct dw_pcie *pci = pcie->pci;
Minghuan Lian7af4ce32015-10-16 15:19:16 +080042 u32 header_type;
43
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053044 header_type = ioread8(pci->dbi_base + PCI_HEADER_TYPE);
Minghuan Lian7af4ce32015-10-16 15:19:16 +080045 header_type &= 0x7f;
46
47 return header_type == PCI_HEADER_TYPE_BRIDGE;
48}
49
Minghuan Lian5192ec72015-10-16 15:19:19 +080050/* Clear multi-function bit */
51static void ls_pcie_clear_multifunction(struct ls_pcie *pcie)
52{
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053053 struct dw_pcie *pci = pcie->pci;
54
55 iowrite8(PCI_HEADER_TYPE_BRIDGE, pci->dbi_base + PCI_HEADER_TYPE);
Minghuan Lian5192ec72015-10-16 15:19:19 +080056}
57
Minghuan Lian1195c1032016-02-29 17:24:15 -060058/* Drop MSG TLP except for Vendor MSG */
59static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
60{
61 u32 val;
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053062 struct dw_pcie *pci = pcie->pci;
Minghuan Lian1195c1032016-02-29 17:24:15 -060063
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053064 val = ioread32(pci->dbi_base + PCIE_STRFMR1);
Minghuan Lian1195c1032016-02-29 17:24:15 -060065 val &= 0xDFFFFFFF;
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +053066 iowrite32(val, pci->dbi_base + PCIE_STRFMR1);
Minghuan Lian1195c1032016-02-29 17:24:15 -060067}
68
Minghuan Lian84d897d2017-10-12 17:44:48 +080069/* Forward error response of outbound non-posted requests */
70static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
71{
72 struct dw_pcie *pci = pcie->pci;
73
74 iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
75}
76
Hou Zhiqiangba95a822017-08-28 18:52:56 +080077static int ls_pcie_host_init(struct pcie_port *pp)
78{
79 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
80 struct ls_pcie *pcie = to_ls_pcie(pci);
81
Minghuan Lian84d897d2017-10-12 17:44:48 +080082 ls_pcie_fix_error_response(pcie);
Hou Zhiqiang4a2745d2017-08-28 18:52:58 +080083
Hou Zhiqiange44abfe2017-08-28 18:52:59 +080084 dw_pcie_dbi_ro_wr_en(pci);
Hou Zhiqiangba95a822017-08-28 18:52:56 +080085 ls_pcie_clear_multifunction(pcie);
Hou Zhiqiange44abfe2017-08-28 18:52:59 +080086 dw_pcie_dbi_ro_wr_dis(pci);
Hou Zhiqiangba95a822017-08-28 18:52:56 +080087
88 ls_pcie_drop_msg_tlp(pcie);
89
Hou Zhiqiangba95a822017-08-28 18:52:56 +080090 return 0;
91}
92
Jisheng Zhang4ab2e7c2017-06-05 16:53:46 +080093static const struct dw_pcie_host_ops ls_pcie_host_ops = {
Minghuan Lian5192ec72015-10-16 15:19:19 +080094 .host_init = ls_pcie_host_init,
95};
96
Minghuan Liand6463342015-10-16 15:19:17 +080097static const struct of_device_id ls_pcie_of_match[] = {
Hou Zhiqiangd23f0c12021-12-24 17:40:00 +080098 { .compatible = "fsl,ls1012a-pcie", },
99 { .compatible = "fsl,ls1021a-pcie", },
100 { .compatible = "fsl,ls1028a-pcie", },
101 { .compatible = "fsl,ls1043a-pcie", },
102 { .compatible = "fsl,ls1046a-pcie", },
103 { .compatible = "fsl,ls2080a-pcie", },
104 { .compatible = "fsl,ls2085a-pcie", },
105 { .compatible = "fsl,ls2088a-pcie", },
106 { .compatible = "fsl,ls1088a-pcie", },
Minghuan Liand6463342015-10-16 15:19:17 +0800107 { },
108};
Minghuan Liand6463342015-10-16 15:19:17 +0800109
Michael Walle7007b742021-01-20 11:52:46 +0100110static int ls_pcie_probe(struct platform_device *pdev)
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800111{
Bjorn Helgaasc11125e2016-10-06 13:38:05 -0500112 struct device *dev = &pdev->dev;
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +0530113 struct dw_pcie *pci;
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800114 struct ls_pcie *pcie;
115 struct resource *dbi_base;
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800116
Bjorn Helgaasc11125e2016-10-06 13:38:05 -0500117 pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800118 if (!pcie)
119 return -ENOMEM;
120
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +0530121 pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
122 if (!pci)
123 return -ENOMEM;
124
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +0530125 pci->dev = dev;
Hou Zhiqiangd23f0c12021-12-24 17:40:00 +0800126 pci->pp.ops = &ls_pcie_host_ops;
Bjorn Helgaasfefe6732016-10-06 13:38:06 -0500127
Guenter Roeckc0464062017-02-25 02:08:12 -0800128 pcie->pci = pci;
129
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800130 dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
Lorenzo Pieralisi01bd4892017-04-19 17:49:08 +0100131 pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
Kishon Vijay Abraham I442ec4c2017-02-15 18:48:14 +0530132 if (IS_ERR(pci->dbi_base))
133 return PTR_ERR(pci->dbi_base);
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800134
Minghuan Lian7af4ce32015-10-16 15:19:16 +0800135 if (!ls_pcie_is_bridge(pcie))
136 return -ENODEV;
137
Kishon Vijay Abraham I9bcf0a62017-02-15 18:48:11 +0530138 platform_set_drvdata(pdev, pcie);
139
Rob Herring60f5b732020-11-05 15:11:56 -0600140 return dw_pcie_host_init(&pci->pp);
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800141}
142
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800143static struct platform_driver ls_pcie_driver = {
Michael Walle7007b742021-01-20 11:52:46 +0100144 .probe = ls_pcie_probe,
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800145 .driver = {
146 .name = "layerscape-pcie",
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800147 .of_match_table = ls_pcie_of_match,
Brian Norrisa5f40e82017-04-20 15:36:25 -0500148 .suppress_bind_attrs = true,
Minghuan Lian62d0ff832014-11-05 16:45:11 +0800149 },
150};
Michael Walle7007b742021-01-20 11:52:46 +0100151builtin_platform_driver(ls_pcie_driver);