1 // SPDX-License-Identifier: GPL-2.0
3 * Loongson PCI Host Controller Driver
5 * Copyright (C) 2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
9 #include <linux/of_pci.h>
10 #include <linux/pci.h>
11 #include <linux/pci_ids.h>
12 #include <linux/pci-acpi.h>
13 #include <linux/pci-ecam.h>
18 #define DEV_LS2K_PCIE_PORT0 0x1a05
19 #define DEV_LS7A_PCIE_PORT0 0x7a09
20 #define DEV_LS7A_PCIE_PORT1 0x7a19
21 #define DEV_LS7A_PCIE_PORT2 0x7a29
22 #define DEV_LS7A_PCIE_PORT3 0x7a39
23 #define DEV_LS7A_PCIE_PORT4 0x7a49
24 #define DEV_LS7A_PCIE_PORT5 0x7a59
25 #define DEV_LS7A_PCIE_PORT6 0x7a69
27 #define DEV_LS2K_APB 0x7a02
28 #define DEV_LS7A_GMAC 0x7a03
29 #define DEV_LS7A_DC1 0x7a06
30 #define DEV_LS7A_LPC 0x7a0c
31 #define DEV_LS7A_AHCI 0x7a08
32 #define DEV_LS7A_CONF 0x7a10
33 #define DEV_LS7A_GNET 0x7a13
34 #define DEV_LS7A_EHCI 0x7a14
35 #define DEV_LS7A_DC2 0x7a36
36 #define DEV_LS7A_HDMI 0x7a37
38 #define FLAG_CFG0 BIT(0)
39 #define FLAG_CFG1 BIT(1)
40 #define FLAG_DEV_FIX BIT(2)
41 #define FLAG_DEV_HIDDEN BIT(3)
43 struct loongson_pci_data
{
49 void __iomem
*cfg0_base
;
50 void __iomem
*cfg1_base
;
51 struct platform_device
*pdev
;
52 const struct loongson_pci_data
*data
;
55 /* Fixup wrong class code in PCIe bridges */
56 static void bridge_class_quirk(struct pci_dev
*dev
)
58 dev
->class = PCI_CLASS_BRIDGE_PCI_NORMAL
;
60 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
61 DEV_LS7A_PCIE_PORT0
, bridge_class_quirk
);
62 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
63 DEV_LS7A_PCIE_PORT1
, bridge_class_quirk
);
64 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
65 DEV_LS7A_PCIE_PORT2
, bridge_class_quirk
);
67 static void system_bus_quirk(struct pci_dev
*pdev
)
70 * The address space consumed by these devices is outside the
71 * resources of the host bridge.
73 pdev
->mmio_always_on
= 1;
74 pdev
->non_compliant_bars
= 1;
76 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
77 DEV_LS2K_APB
, system_bus_quirk
);
78 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
79 DEV_LS7A_CONF
, system_bus_quirk
);
80 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
81 DEV_LS7A_LPC
, system_bus_quirk
);
84 * Some Loongson PCIe ports have hardware limitations on their Maximum Read
85 * Request Size. They can't handle anything larger than this. Sane
86 * firmware will set proper MRRS at boot, so we only need no_inc_mrrs for
87 * bridges. However, some MIPS Loongson firmware doesn't set MRRS properly,
88 * so we have to enforce maximum safe MRRS, which is 256 bytes.
91 static void loongson_set_min_mrrs_quirk(struct pci_dev
*pdev
)
93 struct pci_bus
*bus
= pdev
->bus
;
94 struct pci_dev
*bridge
;
95 static const struct pci_device_id bridge_devids
[] = {
96 { PCI_VDEVICE(LOONGSON
, DEV_LS2K_PCIE_PORT0
) },
97 { PCI_VDEVICE(LOONGSON
, DEV_LS7A_PCIE_PORT0
) },
98 { PCI_VDEVICE(LOONGSON
, DEV_LS7A_PCIE_PORT1
) },
99 { PCI_VDEVICE(LOONGSON
, DEV_LS7A_PCIE_PORT2
) },
100 { PCI_VDEVICE(LOONGSON
, DEV_LS7A_PCIE_PORT3
) },
101 { PCI_VDEVICE(LOONGSON
, DEV_LS7A_PCIE_PORT4
) },
102 { PCI_VDEVICE(LOONGSON
, DEV_LS7A_PCIE_PORT5
) },
103 { PCI_VDEVICE(LOONGSON
, DEV_LS7A_PCIE_PORT6
) },
107 /* look for the matching bridge */
108 while (!pci_is_root_bus(bus
)) {
112 if (pci_match_id(bridge_devids
, bridge
)) {
113 if (pcie_get_readrq(pdev
) > 256) {
114 pci_info(pdev
, "limiting MRRS to 256\n");
115 pcie_set_readrq(pdev
, 256);
121 DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID
, PCI_ANY_ID
, loongson_set_min_mrrs_quirk
);
124 static void loongson_mrrs_quirk(struct pci_dev
*pdev
)
126 struct pci_host_bridge
*bridge
= pci_find_host_bridge(pdev
->bus
);
128 bridge
->no_inc_mrrs
= 1;
130 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
131 DEV_LS2K_PCIE_PORT0
, loongson_mrrs_quirk
);
132 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
133 DEV_LS7A_PCIE_PORT0
, loongson_mrrs_quirk
);
134 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
135 DEV_LS7A_PCIE_PORT1
, loongson_mrrs_quirk
);
136 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
137 DEV_LS7A_PCIE_PORT2
, loongson_mrrs_quirk
);
138 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
139 DEV_LS7A_PCIE_PORT3
, loongson_mrrs_quirk
);
140 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
141 DEV_LS7A_PCIE_PORT4
, loongson_mrrs_quirk
);
142 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
143 DEV_LS7A_PCIE_PORT5
, loongson_mrrs_quirk
);
144 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON
,
145 DEV_LS7A_PCIE_PORT6
, loongson_mrrs_quirk
);
147 static void loongson_pci_pin_quirk(struct pci_dev
*pdev
)
149 pdev
->pin
= 1 + (PCI_FUNC(pdev
->devfn
) & 3);
151 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
,
152 DEV_LS7A_DC1
, loongson_pci_pin_quirk
);
153 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
,
154 DEV_LS7A_DC2
, loongson_pci_pin_quirk
);
155 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
,
156 DEV_LS7A_GMAC
, loongson_pci_pin_quirk
);
157 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
,
158 DEV_LS7A_AHCI
, loongson_pci_pin_quirk
);
159 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
,
160 DEV_LS7A_EHCI
, loongson_pci_pin_quirk
);
161 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
,
162 DEV_LS7A_GNET
, loongson_pci_pin_quirk
);
163 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
,
164 DEV_LS7A_HDMI
, loongson_pci_pin_quirk
);
166 static void loongson_pci_msi_quirk(struct pci_dev
*dev
)
168 u16 val
, class = dev
->class >> 8;
170 if (class != PCI_CLASS_BRIDGE_HOST
)
173 pci_read_config_word(dev
, dev
->msi_cap
+ PCI_MSI_FLAGS
, &val
);
174 val
|= PCI_MSI_FLAGS_ENABLE
;
175 pci_write_config_word(dev
, dev
->msi_cap
+ PCI_MSI_FLAGS
, val
);
177 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON
, DEV_LS7A_PCIE_PORT5
, loongson_pci_msi_quirk
);
179 static struct loongson_pci
*pci_bus_to_loongson_pci(struct pci_bus
*bus
)
181 struct pci_config_window
*cfg
;
184 return (struct loongson_pci
*)(bus
->sysdata
);
187 return (struct loongson_pci
*)(cfg
->priv
);
190 static void __iomem
*cfg0_map(struct loongson_pci
*priv
, struct pci_bus
*bus
,
191 unsigned int devfn
, int where
)
193 unsigned long addroff
= 0x0;
194 unsigned char busnum
= bus
->number
;
196 if (!pci_is_root_bus(bus
)) {
197 addroff
|= BIT(24); /* Type 1 Access */
198 addroff
|= (busnum
<< 16);
200 addroff
|= (devfn
<< 8) | where
;
201 return priv
->cfg0_base
+ addroff
;
204 static void __iomem
*cfg1_map(struct loongson_pci
*priv
, struct pci_bus
*bus
,
205 unsigned int devfn
, int where
)
207 unsigned long addroff
= 0x0;
208 unsigned char busnum
= bus
->number
;
210 if (!pci_is_root_bus(bus
)) {
211 addroff
|= BIT(28); /* Type 1 Access */
212 addroff
|= (busnum
<< 16);
214 addroff
|= (devfn
<< 8) | (where
& 0xff) | ((where
& 0xf00) << 16);
215 return priv
->cfg1_base
+ addroff
;
218 static bool pdev_may_exist(struct pci_bus
*bus
, unsigned int device
,
219 unsigned int function
)
221 return !(pci_is_root_bus(bus
) &&
222 (device
>= 9 && device
<= 20) && (function
> 0));
225 static void __iomem
*pci_loongson_map_bus(struct pci_bus
*bus
,
226 unsigned int devfn
, int where
)
228 unsigned int device
= PCI_SLOT(devfn
);
229 unsigned int function
= PCI_FUNC(devfn
);
230 struct loongson_pci
*priv
= pci_bus_to_loongson_pci(bus
);
233 * Do not read more than one device on the bus other than
236 if ((priv
->data
->flags
& FLAG_DEV_FIX
) && bus
->self
) {
237 if (!pci_is_root_bus(bus
) && (device
> 0))
241 /* Don't access non-existent devices */
242 if (priv
->data
->flags
& FLAG_DEV_HIDDEN
) {
243 if (!pdev_may_exist(bus
, device
, function
))
247 /* CFG0 can only access standard space */
248 if (where
< PCI_CFG_SPACE_SIZE
&& priv
->cfg0_base
)
249 return cfg0_map(priv
, bus
, devfn
, where
);
251 /* CFG1 can access extended space */
252 if (where
< PCI_CFG_SPACE_EXP_SIZE
&& priv
->cfg1_base
)
253 return cfg1_map(priv
, bus
, devfn
, where
);
260 static int loongson_map_irq(const struct pci_dev
*dev
, u8 slot
, u8 pin
)
265 irq
= of_irq_parse_and_map_pci(dev
, slot
, pin
);
269 /* Care i8259 legacy systems */
270 pci_read_config_byte(dev
, PCI_INTERRUPT_LINE
, &val
);
271 /* i8259 only have 15 IRQs */
278 /* LS2K/LS7A accept 8/16/32-bit PCI config operations */
279 static struct pci_ops loongson_pci_ops
= {
280 .map_bus
= pci_loongson_map_bus
,
281 .read
= pci_generic_config_read
,
282 .write
= pci_generic_config_write
,
285 /* RS780/SR5690 only accept 32-bit PCI config operations */
286 static struct pci_ops loongson_pci_ops32
= {
287 .map_bus
= pci_loongson_map_bus
,
288 .read
= pci_generic_config_read32
,
289 .write
= pci_generic_config_write32
,
292 static const struct loongson_pci_data ls2k_pci_data
= {
293 .flags
= FLAG_CFG1
| FLAG_DEV_FIX
| FLAG_DEV_HIDDEN
,
294 .ops
= &loongson_pci_ops
,
297 static const struct loongson_pci_data ls7a_pci_data
= {
298 .flags
= FLAG_CFG1
| FLAG_DEV_FIX
| FLAG_DEV_HIDDEN
,
299 .ops
= &loongson_pci_ops
,
302 static const struct loongson_pci_data rs780e_pci_data
= {
304 .ops
= &loongson_pci_ops32
,
307 static const struct of_device_id loongson_pci_of_match
[] = {
308 { .compatible
= "loongson,ls2k-pci",
309 .data
= &ls2k_pci_data
, },
310 { .compatible
= "loongson,ls7a-pci",
311 .data
= &ls7a_pci_data
, },
312 { .compatible
= "loongson,rs780e-pci",
313 .data
= &rs780e_pci_data
, },
317 static int loongson_pci_probe(struct platform_device
*pdev
)
319 struct loongson_pci
*priv
;
320 struct device
*dev
= &pdev
->dev
;
321 struct device_node
*node
= dev
->of_node
;
322 struct pci_host_bridge
*bridge
;
323 struct resource
*regs
;
328 bridge
= devm_pci_alloc_host_bridge(dev
, sizeof(*priv
));
332 priv
= pci_host_bridge_priv(bridge
);
334 priv
->data
= of_device_get_match_data(dev
);
336 if (priv
->data
->flags
& FLAG_CFG0
) {
337 regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
339 dev_err(dev
, "missing mem resources for cfg0\n");
341 priv
->cfg0_base
= devm_pci_remap_cfg_resource(dev
, regs
);
342 if (IS_ERR(priv
->cfg0_base
))
343 return PTR_ERR(priv
->cfg0_base
);
347 if (priv
->data
->flags
& FLAG_CFG1
) {
348 regs
= platform_get_resource(pdev
, IORESOURCE_MEM
, 1);
350 dev_info(dev
, "missing mem resource for cfg1\n");
352 priv
->cfg1_base
= devm_pci_remap_cfg_resource(dev
, regs
);
353 if (IS_ERR(priv
->cfg1_base
))
354 priv
->cfg1_base
= NULL
;
358 bridge
->sysdata
= priv
;
359 bridge
->ops
= priv
->data
->ops
;
360 bridge
->map_irq
= loongson_map_irq
;
362 return pci_host_probe(bridge
);
365 static struct platform_driver loongson_pci_driver
= {
367 .name
= "loongson-pci",
368 .of_match_table
= loongson_pci_of_match
,
370 .probe
= loongson_pci_probe
,
372 builtin_platform_driver(loongson_pci_driver
);
378 static int loongson_pci_ecam_init(struct pci_config_window
*cfg
)
380 struct device
*dev
= cfg
->parent
;
381 struct loongson_pci
*priv
;
382 struct loongson_pci_data
*data
;
384 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
388 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
393 data
->flags
= FLAG_CFG1
| FLAG_DEV_HIDDEN
;
395 priv
->cfg1_base
= cfg
->win
- (cfg
->busr
.start
<< 16);
400 const struct pci_ecam_ops loongson_pci_ecam_ops
= {
402 .init
= loongson_pci_ecam_init
,
404 .map_bus
= pci_loongson_map_bus
,
405 .read
= pci_generic_config_read
,
406 .write
= pci_generic_config_write
,