1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Loongson PCI Host Controller Driver
4 *
5 * Copyright (C) 2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
6 */
7
8#include <linux/of_device.h>
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>
14
15#include "../pci.h"
16
17/* Device IDs */
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
26
27#define DEV_LS2K_APB	0x7a02
28#define DEV_LS7A_CONF	0x7a10
29#define DEV_LS7A_LPC	0x7a0c
30
31#define FLAG_CFG0	BIT(0)
32#define FLAG_CFG1	BIT(1)
33#define FLAG_DEV_FIX	BIT(2)
34
35struct pci_controller_data {
36	u32 flags;
37	struct pci_ops *ops;
38};
39
40struct loongson_pci {
41	void __iomem *cfg0_base;
42	void __iomem *cfg1_base;
43	struct platform_device *pdev;
44	struct pci_controller_data *data;
45};
46
47/* Fixup wrong class code in PCIe bridges */
48static void bridge_class_quirk(struct pci_dev *dev)
49{
50	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
51}
52DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
53			DEV_LS7A_PCIE_PORT0, bridge_class_quirk);
54DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
55			DEV_LS7A_PCIE_PORT1, bridge_class_quirk);
56DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
57			DEV_LS7A_PCIE_PORT2, bridge_class_quirk);
58
59static void system_bus_quirk(struct pci_dev *pdev)
60{
61	/*
62	 * The address space consumed by these devices is outside the
63	 * resources of the host bridge.
64	 */
65	pdev->mmio_always_on = 1;
66	pdev->non_compliant_bars = 1;
67}
68DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
69			DEV_LS2K_APB, system_bus_quirk);
70DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
71			DEV_LS7A_CONF, system_bus_quirk);
72DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
73			DEV_LS7A_LPC, system_bus_quirk);
74
75/*
76 * Some Loongson PCIe ports have hardware limitations on their Maximum Read
77 * Request Size. They can't handle anything larger than this.  Sane
78 * firmware will set proper MRRS at boot, so we only need no_inc_mrrs for
79 * bridges. However, some MIPS Loongson firmware doesn't set MRRS properly,
80 * so we have to enforce maximum safe MRRS, which is 256 bytes.
81 */
82#ifdef CONFIG_MIPS
83static void loongson_set_min_mrrs_quirk(struct pci_dev *pdev)
84{
85	struct pci_bus *bus = pdev->bus;
86	struct pci_dev *bridge;
87	static const struct pci_device_id bridge_devids[] = {
88		{ PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
89		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
90		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
91		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
92		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
93		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
94		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
95		{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
96		{ 0, },
97	};
98
99	/* look for the matching bridge */
100	while (!pci_is_root_bus(bus)) {
101		bridge = bus->self;
102		bus = bus->parent;
103
104		if (pci_match_id(bridge_devids, bridge)) {
105			if (pcie_get_readrq(pdev) > 256) {
106				pci_info(pdev, "limiting MRRS to 256\n");
107				pcie_set_readrq(pdev, 256);
108			}
109			break;
110		}
111	}
112}
113DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_set_min_mrrs_quirk);
114#endif
115
116static void loongson_mrrs_quirk(struct pci_dev *pdev)
117{
118	struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
119
120	bridge->no_inc_mrrs = 1;
121}
122DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
123			DEV_LS2K_PCIE_PORT0, loongson_mrrs_quirk);
124DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
125			DEV_LS7A_PCIE_PORT0, loongson_mrrs_quirk);
126DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
127			DEV_LS7A_PCIE_PORT1, loongson_mrrs_quirk);
128DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
129			DEV_LS7A_PCIE_PORT2, loongson_mrrs_quirk);
130DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
131			DEV_LS7A_PCIE_PORT3, loongson_mrrs_quirk);
132DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
133			DEV_LS7A_PCIE_PORT4, loongson_mrrs_quirk);
134DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
135			DEV_LS7A_PCIE_PORT5, loongson_mrrs_quirk);
136DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
137			DEV_LS7A_PCIE_PORT6, loongson_mrrs_quirk);
138
139static void loongson_pci_pin_quirk(struct pci_dev *pdev)
140{
141	pdev->pin = 1 + (PCI_FUNC(pdev->devfn) & 3);
142}
143DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
144			PCI_DEVICE_ID_LOONGSON_AHCI, loongson_pci_pin_quirk);
145DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
146			PCI_DEVICE_ID_LOONGSON_EHCI, loongson_pci_pin_quirk);
147DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
148			PCI_DEVICE_ID_LOONGSON_OHCI, loongson_pci_pin_quirk);
149DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
150			PCI_DEVICE_ID_LOONGSON_DC1, loongson_pci_pin_quirk);
151DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
152			PCI_DEVICE_ID_LOONGSON_DC2, loongson_pci_pin_quirk);
153DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
154			PCI_DEVICE_ID_LOONGSON_GPU, loongson_pci_pin_quirk);
155DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
156			PCI_DEVICE_ID_LOONGSON_HDMI, loongson_pci_pin_quirk);
157DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
158			PCI_DEVICE_ID_LOONGSON_GMAC, loongson_pci_pin_quirk);
159DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
160			PCI_DEVICE_ID_LOONGSON_GNET, loongson_pci_pin_quirk);
161
162static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus)
163{
164	struct pci_config_window *cfg;
165
166	if (acpi_disabled)
167		return (struct loongson_pci *)(bus->sysdata);
168
169	cfg = bus->sysdata;
170	return (struct loongson_pci *)(cfg->priv);
171}
172
173static void __iomem *cfg0_map(struct loongson_pci *priv,
174			      struct pci_bus *bus, unsigned int devfn, int where)
175{
176	unsigned long addroff = 0x0;
177	unsigned char busnum = bus->number;
178
179	if (!pci_is_root_bus(bus)) {
180		addroff |= BIT(24); /* Type 1 Access */
181		addroff |= (busnum << 16);
182	}
183	addroff |= (devfn << 8) | where;
184	return priv->cfg0_base + addroff;
185}
186
187static void __iomem *cfg1_map(struct loongson_pci *priv,
188			      struct pci_bus *bus, unsigned int devfn, int where)
189{
190	unsigned long addroff = 0x0;
191	unsigned char busnum = bus->number;
192
193	if (!pci_is_root_bus(bus)) {
194		addroff |= BIT(28); /* Type 1 Access */
195		addroff |= (busnum << 16);
196	}
197	addroff |= (devfn << 8) | (where & 0xff) | ((where & 0xf00) << 16);
198	return priv->cfg1_base + addroff;
199}
200
201static void __iomem *pci_loongson_map_bus(struct pci_bus *bus, unsigned int devfn,
202			       int where)
203{
204	unsigned int device = PCI_SLOT(devfn);
205	unsigned int function = PCI_FUNC(devfn);
206	struct loongson_pci *priv = pci_bus_to_loongson_pci(bus);
207
208	/*
209	 * Do not read more than one device on the bus other than
210	 * the host bus. For our hardware the root bus is always bus 0.
211	 */
212	if ((priv->data->flags & FLAG_DEV_FIX) && bus->self) {
213		if (!pci_is_root_bus(bus) && (device > 0))
214			return NULL;
215	}
216
217	/* Don't access unexisting devices */
218	if (pci_is_root_bus(bus) && (device >= 9 && device <= 20 && function > 0))
219		return NULL;
220
221	/* CFG0 can only access standard space */
222	if (where < PCI_CFG_SPACE_SIZE && priv->cfg0_base)
223		return cfg0_map(priv, bus, devfn, where);
224
225	/* CFG1 can access extended space */
226	if (where < PCI_CFG_SPACE_EXP_SIZE && priv->cfg1_base)
227		return cfg1_map(priv, bus, devfn, where);
228
229	return NULL;
230}
231
232#ifdef CONFIG_OF
233
234static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
235{
236	int irq;
237	u8 val;
238
239	irq = of_irq_parse_and_map_pci(dev, slot, pin);
240	if (irq > 0)
241		return irq;
242
243	/* Care i8259 legacy systems */
244	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &val);
245	/* i8259 only have 15 IRQs */
246	if (val > 15)
247		return 0;
248
249	return val;
250}
251
252/* LS2K/LS7A accept 8/16/32-bit PCI config operations */
253static struct pci_ops loongson_pci_ops = {
254	.map_bus = pci_loongson_map_bus,
255	.read	= pci_generic_config_read,
256	.write	= pci_generic_config_write,
257};
258
259/* RS780/SR5690 only accept 32-bit PCI config operations */
260static struct pci_ops loongson_pci_ops32 = {
261	.map_bus = pci_loongson_map_bus,
262	.read	= pci_generic_config_read32,
263	.write	= pci_generic_config_write32,
264};
265
266static const struct pci_controller_data ls2k_pci_data = {
267	.flags = FLAG_CFG1 | FLAG_DEV_FIX,
268	.ops = &loongson_pci_ops,
269};
270
271static const struct pci_controller_data ls7a_pci_data = {
272	.flags = FLAG_CFG1 | FLAG_DEV_FIX,
273	.ops = &loongson_pci_ops,
274};
275
276static const struct pci_controller_data rs780e_pci_data = {
277	.flags = FLAG_CFG0,
278	.ops = &loongson_pci_ops32,
279};
280
281static const struct of_device_id loongson_pci_of_match[] = {
282	{ .compatible = "loongson,ls2k-pci",
283		.data = (void *)&ls2k_pci_data, },
284	{ .compatible = "loongson,ls7a-pci",
285		.data = (void *)&ls7a_pci_data, },
286	{ .compatible = "loongson,rs780e-pci",
287		.data = (void *)&rs780e_pci_data, },
288	{}
289};
290
291static int loongson_pci_probe(struct platform_device *pdev)
292{
293	struct loongson_pci *priv;
294	struct device *dev = &pdev->dev;
295	struct device_node *node = dev->of_node;
296	struct pci_host_bridge *bridge;
297	struct resource *regs;
298
299	if (!node)
300		return -ENODEV;
301
302	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*priv));
303	if (!bridge)
304		return -ENODEV;
305
306	priv = pci_host_bridge_priv(bridge);
307	priv->pdev = pdev;
308	priv->data = (struct pci_controller_data *)of_device_get_match_data(dev);
309
310	if (priv->data->flags & FLAG_CFG0) {
311		regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
312		if (!regs)
313			dev_err(dev, "missing mem resources for cfg0\n");
314		else {
315			priv->cfg0_base = devm_pci_remap_cfg_resource(dev, regs);
316			if (IS_ERR(priv->cfg0_base))
317				return PTR_ERR(priv->cfg0_base);
318		}
319	}
320
321	if (priv->data->flags & FLAG_CFG1) {
322		regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
323		if (!regs)
324			dev_info(dev, "missing mem resource for cfg1\n");
325		else {
326			priv->cfg1_base = devm_pci_remap_cfg_resource(dev, regs);
327			if (IS_ERR(priv->cfg1_base))
328				priv->cfg1_base = NULL;
329		}
330	}
331
332	bridge->sysdata = priv;
333	bridge->ops = priv->data->ops;
334	bridge->map_irq = loongson_map_irq;
335
336	return pci_host_probe(bridge);
337}
338
339static struct platform_driver loongson_pci_driver = {
340	.driver = {
341		.name = "loongson-pci",
342		.of_match_table = loongson_pci_of_match,
343	},
344	.probe = loongson_pci_probe,
345};
346builtin_platform_driver(loongson_pci_driver);
347
348#endif
349
350#ifdef CONFIG_ACPI
351
352static int loongson_pci_ecam_init(struct pci_config_window *cfg)
353{
354	struct device *dev = cfg->parent;
355	struct loongson_pci *priv;
356	struct pci_controller_data *data;
357
358	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
359	if (!priv)
360		return -ENOMEM;
361
362	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
363	if (!data)
364		return -ENOMEM;
365
366	cfg->priv = priv;
367	data->flags = FLAG_CFG1;
368	priv->data = data;
369	priv->cfg1_base = cfg->win - (cfg->busr.start << 16);
370
371	return 0;
372}
373
374const struct pci_ecam_ops loongson_pci_ecam_ops = {
375	.bus_shift = 16,
376	.init	   = loongson_pci_ecam_init,
377	.pci_ops   = {
378		.map_bus = pci_loongson_map_bus,
379		.read	 = pci_generic_config_read,
380		.write	 = pci_generic_config_write,
381	}
382};
383
384#endif
385