Skip to content

Commit d52e027

Browse files
committed
Merge branch 'pci/controller/dwc-andes-qilai'
- Add Andes QiLai SoC PCIe host driver support (Randolph Lin) * pci/controller/dwc-andes-qilai: PCI: qilai: Add Andes QiLai SoC PCIe host driver support dt-bindings: PCI: Add Andes QiLai PCIe support # Conflicts: # drivers/pci/controller/dwc/Makefile
2 parents 9cba284 + df5d8fb commit d52e027

5 files changed

Lines changed: 305 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/pci/andestech,qilai-pcie.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Andes QiLai PCIe host controller
8+
9+
description:
10+
Andes QiLai PCIe host controller is based on the Synopsys DesignWare
11+
PCI core.
12+
13+
maintainers:
14+
- Randolph Lin <randolph@andestech.com>
15+
16+
allOf:
17+
- $ref: /schemas/pci/snps,dw-pcie.yaml#
18+
19+
properties:
20+
compatible:
21+
const: andestech,qilai-pcie
22+
23+
reg:
24+
items:
25+
- description: Data Bus Interface (DBI) registers.
26+
- description: APB registers.
27+
- description: PCIe configuration space region.
28+
29+
reg-names:
30+
items:
31+
- const: dbi
32+
- const: apb
33+
- const: config
34+
35+
dma-coherent: true
36+
37+
ranges:
38+
maxItems: 2
39+
40+
interrupts:
41+
maxItems: 1
42+
43+
interrupt-names:
44+
items:
45+
- const: msi
46+
47+
required:
48+
- reg
49+
- reg-names
50+
- interrupts
51+
- interrupt-names
52+
53+
unevaluatedProperties: false
54+
55+
examples:
56+
- |
57+
#include <dt-bindings/interrupt-controller/irq.h>
58+
59+
soc {
60+
#address-cells = <2>;
61+
#size-cells = <2>;
62+
63+
pcie@80000000 {
64+
compatible = "andestech,qilai-pcie";
65+
device_type = "pci";
66+
reg = <0x0 0x80000000 0x0 0x20000000>,
67+
<0x0 0x04000000 0x0 0x00001000>,
68+
<0x0 0x00000000 0x0 0x00010000>;
69+
reg-names = "dbi", "apb", "config";
70+
dma-coherent;
71+
72+
linux,pci-domain = <0>;
73+
#address-cells = <3>;
74+
#size-cells = <2>;
75+
ranges = <0x02000000 0x00 0x10000000 0x00 0x10000000 0x00 0xf0000000>,
76+
<0x43000000 0x01 0x00000000 0x01 0x00000000 0x02 0x00000000>;
77+
78+
#interrupt-cells = <1>;
79+
interrupts = <0xf>;
80+
interrupt-names = "msi";
81+
interrupt-parent = <&plic0>;
82+
interrupt-map-mask = <0 0 0 0>;
83+
interrupt-map = <0 0 0 1 &plic0 0xf IRQ_TYPE_LEVEL_HIGH>,
84+
<0 0 0 2 &plic0 0xf IRQ_TYPE_LEVEL_HIGH>,
85+
<0 0 0 3 &plic0 0xf IRQ_TYPE_LEVEL_HIGH>,
86+
<0 0 0 4 &plic0 0xf IRQ_TYPE_LEVEL_HIGH>;
87+
};
88+
};
89+
...

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20128,6 +20128,13 @@ S: Supported
2012820128
F: Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
2012920129
F: drivers/pci/controller/pcie-altera.c
2013020130

20131+
PCI DRIVER FOR ANDES QILAI PCIE
20132+
M: Randolph Lin <randolph@andestech.com>
20133+
L: linux-pci@vger.kernel.org
20134+
S: Maintained
20135+
F: Documentation/devicetree/bindings/pci/andestech,qilai-pcie.yaml
20136+
F: drivers/pci/controller/dwc/pcie-andes-qilai.c
20137+
2013120138
PCI DRIVER FOR APPLIEDMICRO XGENE
2013220139
M: Toan Le <toan@os.amperecomputing.com>
2013320140
L: linux-pci@vger.kernel.org

drivers/pci/controller/dwc/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ config PCI_MESON
6161
and therefore the driver re-uses the DesignWare core functions to
6262
implement the driver.
6363

64+
config PCIE_ANDES_QILAI
65+
tristate "Andes QiLai PCIe controller"
66+
depends on ARCH_ANDES || COMPILE_TEST
67+
depends on PCI_MSI
68+
select PCIE_DW_HOST
69+
help
70+
Say Y here to enable PCIe controller support on Andes QiLai SoCs,
71+
which operate in Root Complex mode. The Andes QiLai SoC PCIe
72+
controller is based on DesignWare IP and therefore the driver
73+
re-uses the DesignWare core functions to implement the driver.
74+
6475
config PCIE_ARTPEC6
6576
bool
6677

drivers/pci/controller/dwc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o
55
obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o
66
obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
77
obj-$(CONFIG_PCIE_AMD_MDB) += pcie-amd-mdb.o
8+
obj-$(CONFIG_PCIE_ANDES_QILAI) += pcie-andes-qilai.o
89
obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
910
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
1011
obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Driver for the PCIe Controller in QiLai from Andes
4+
*
5+
* Copyright (C) 2026 Andes Technology Corporation
6+
*/
7+
8+
#include <linux/bitfield.h>
9+
#include <linux/bits.h>
10+
#include <linux/kernel.h>
11+
#include <linux/module.h>
12+
#include <linux/pci.h>
13+
#include <linux/platform_device.h>
14+
#include <linux/pm_runtime.h>
15+
#include <linux/types.h>
16+
17+
#include "pcie-designware.h"
18+
19+
#define PCIE_INTR_CONTROL1 0x15c
20+
#define PCIE_MSI_CTRL_INT_EN BIT(28)
21+
22+
#define PCIE_LOGIC_COHERENCY_CONTROL3 0x8e8
23+
24+
/*
25+
* Refer to Table A4-5 (Memory type encoding) in the
26+
* AMBA AXI and ACE Protocol Specification.
27+
*
28+
* The selected value corresponds to the Memory type field:
29+
* "Write-back, Read and Write-allocate".
30+
*
31+
* The last three rows in the table A4-5 in
32+
* AMBA AXI and ACE Protocol Specification:
33+
* ARCACHE AWCACHE Memory type
34+
* ------------------------------------------------------------------
35+
* 1111 (0111) 0111 Write-back Read-allocate
36+
* 1011 1111 (1011) Write-back Write-allocate
37+
* 1111 1111 Write-back Read and Write-allocate (selected)
38+
*/
39+
#define IOCP_ARCACHE 0b1111
40+
#define IOCP_AWCACHE 0b1111
41+
42+
#define PCIE_CFG_MSTR_ARCACHE_MODE GENMASK(6, 3)
43+
#define PCIE_CFG_MSTR_AWCACHE_MODE GENMASK(14, 11)
44+
#define PCIE_CFG_MSTR_ARCACHE_VALUE GENMASK(22, 19)
45+
#define PCIE_CFG_MSTR_AWCACHE_VALUE GENMASK(30, 27)
46+
47+
#define PCIE_GEN_CONTROL2 0x54
48+
#define PCIE_CFG_LTSSM_EN BIT(0)
49+
50+
#define PCIE_REGS_PCIE_SII_PM_STATE 0xc0
51+
#define SMLH_LINK_UP BIT(6)
52+
#define RDLH_LINK_UP BIT(7)
53+
54+
struct qilai_pcie {
55+
struct dw_pcie pci;
56+
void __iomem *apb_base;
57+
};
58+
59+
#define to_qilai_pcie(_pci) container_of(_pci, struct qilai_pcie, pci)
60+
61+
static bool qilai_pcie_link_up(struct dw_pcie *pci)
62+
{
63+
struct qilai_pcie *pcie = to_qilai_pcie(pci);
64+
u32 val;
65+
66+
val = readl(pcie->apb_base + PCIE_REGS_PCIE_SII_PM_STATE);
67+
68+
return FIELD_GET(SMLH_LINK_UP, val) && FIELD_GET(RDLH_LINK_UP, val);
69+
}
70+
71+
static int qilai_pcie_start_link(struct dw_pcie *pci)
72+
{
73+
struct qilai_pcie *pcie = to_qilai_pcie(pci);
74+
u32 val;
75+
76+
val = readl(pcie->apb_base + PCIE_GEN_CONTROL2);
77+
val |= PCIE_CFG_LTSSM_EN;
78+
writel(val, pcie->apb_base + PCIE_GEN_CONTROL2);
79+
80+
return 0;
81+
}
82+
83+
static const struct dw_pcie_ops qilai_pcie_ops = {
84+
.link_up = qilai_pcie_link_up,
85+
.start_link = qilai_pcie_start_link,
86+
};
87+
88+
/*
89+
* Set up the QiLai PCIe IOCP (IO Coherence Port) Read/Write Behaviors to the
90+
* Write-Back, Read and Write Allocate mode.
91+
*
92+
* The IOCP HW target is SoC last-level cache (L2 Cache), which serves as the
93+
* system cache. The IOCP HW helps maintain cache monitoring, ensuring that
94+
* the device can snoop data from/to the cache.
95+
*/
96+
static void qilai_pcie_iocp_cache_setup(struct dw_pcie_rp *pp)
97+
{
98+
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
99+
u32 val;
100+
101+
dw_pcie_dbi_ro_wr_en(pci);
102+
103+
val = dw_pcie_readl_dbi(pci, PCIE_LOGIC_COHERENCY_CONTROL3);
104+
FIELD_MODIFY(PCIE_CFG_MSTR_ARCACHE_MODE, &val, IOCP_ARCACHE);
105+
FIELD_MODIFY(PCIE_CFG_MSTR_AWCACHE_MODE, &val, IOCP_AWCACHE);
106+
FIELD_MODIFY(PCIE_CFG_MSTR_ARCACHE_VALUE, &val, IOCP_ARCACHE);
107+
FIELD_MODIFY(PCIE_CFG_MSTR_AWCACHE_VALUE, &val, IOCP_AWCACHE);
108+
dw_pcie_writel_dbi(pci, PCIE_LOGIC_COHERENCY_CONTROL3, val);
109+
110+
dw_pcie_dbi_ro_wr_dis(pci);
111+
}
112+
113+
static void qilai_pcie_enable_msi(struct qilai_pcie *pcie)
114+
{
115+
u32 val;
116+
117+
val = readl(pcie->apb_base + PCIE_INTR_CONTROL1);
118+
val |= PCIE_MSI_CTRL_INT_EN;
119+
writel(val, pcie->apb_base + PCIE_INTR_CONTROL1);
120+
}
121+
122+
static int qilai_pcie_host_init(struct dw_pcie_rp *pp)
123+
{
124+
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
125+
struct qilai_pcie *pcie = to_qilai_pcie(pci);
126+
127+
qilai_pcie_enable_msi(pcie);
128+
129+
return 0;
130+
}
131+
132+
static void qilai_pcie_host_post_init(struct dw_pcie_rp *pp)
133+
{
134+
qilai_pcie_iocp_cache_setup(pp);
135+
}
136+
137+
static const struct dw_pcie_host_ops qilai_pcie_host_ops = {
138+
.init = qilai_pcie_host_init,
139+
.post_init = qilai_pcie_host_post_init,
140+
};
141+
142+
static int qilai_pcie_probe(struct platform_device *pdev)
143+
{
144+
struct qilai_pcie *pcie;
145+
struct dw_pcie *pci;
146+
struct device *dev = &pdev->dev;
147+
int ret;
148+
149+
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
150+
if (!pcie)
151+
return -ENOMEM;
152+
153+
platform_set_drvdata(pdev, pcie);
154+
155+
pci = &pcie->pci;
156+
pcie->pci.dev = dev;
157+
pcie->pci.ops = &qilai_pcie_ops;
158+
pcie->pci.pp.ops = &qilai_pcie_host_ops;
159+
pci->use_parent_dt_ranges = true;
160+
161+
dw_pcie_cap_set(&pcie->pci, REQ_RES);
162+
163+
pcie->apb_base = devm_platform_ioremap_resource_byname(pdev, "apb");
164+
if (IS_ERR(pcie->apb_base))
165+
return PTR_ERR(pcie->apb_base);
166+
167+
pm_runtime_set_active(dev);
168+
pm_runtime_no_callbacks(dev);
169+
devm_pm_runtime_enable(dev);
170+
171+
ret = dw_pcie_host_init(&pcie->pci.pp);
172+
if (ret)
173+
return dev_err_probe(dev, ret, "Failed to initialize PCIe host\n");
174+
175+
return 0;
176+
}
177+
178+
static const struct of_device_id qilai_pcie_of_match[] = {
179+
{ .compatible = "andestech,qilai-pcie" },
180+
{},
181+
};
182+
MODULE_DEVICE_TABLE(of, qilai_pcie_of_match);
183+
184+
static struct platform_driver qilai_pcie_driver = {
185+
.probe = qilai_pcie_probe,
186+
.driver = {
187+
.name = "qilai-pcie",
188+
.of_match_table = qilai_pcie_of_match,
189+
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
190+
},
191+
};
192+
193+
builtin_platform_driver(qilai_pcie_driver);
194+
195+
MODULE_AUTHOR("Randolph Lin <randolph@andestech.com>");
196+
MODULE_DESCRIPTION("Andes QiLai PCIe driver");
197+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)