1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
4 */
5 #include <linux/kernel.h>
6 #include <linux/init.h>
7 #include <linux/acpi.h>
8 #include <linux/delay.h>
9 #include <linux/types.h>
10 #include <linux/pci.h>
11 #include <linux/vgaarb.h>
12 #include <linux/io-64-nonatomic-lo-hi.h>
13 #include <asm/cacheflush.h>
14 #include <asm/loongson.h>
15
16 #define PCI_DEVICE_ID_LOONGSON_HOST 0x7a00
17 #define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
18 #define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36
19 #define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46
20 #define PCI_DEVICE_ID_LOONGSON_GPU1 0x7a15
21 #define PCI_DEVICE_ID_LOONGSON_GPU2 0x7a25
22 #define PCI_DEVICE_ID_LOONGSON_GPU3 0x7a35
23
raw_pci_read(unsigned int domain,unsigned int bus,unsigned int devfn,int reg,int len,u32 * val)24 int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
25 int reg, int len, u32 *val)
26 {
27 struct pci_bus *bus_tmp = pci_find_bus(domain, bus);
28
29 if (bus_tmp)
30 return bus_tmp->ops->read(bus_tmp, devfn, reg, len, val);
31 return -EINVAL;
32 }
33
raw_pci_write(unsigned int domain,unsigned int bus,unsigned int devfn,int reg,int len,u32 val)34 int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
35 int reg, int len, u32 val)
36 {
37 struct pci_bus *bus_tmp = pci_find_bus(domain, bus);
38
39 if (bus_tmp)
40 return bus_tmp->ops->write(bus_tmp, devfn, reg, len, val);
41 return -EINVAL;
42 }
43
mcfg_addr_init(int node)44 phys_addr_t mcfg_addr_init(int node)
45 {
46 return (((u64)node << 44) | MCFG_EXT_PCICFG_BASE);
47 }
48
pcibios_init(void)49 static int __init pcibios_init(void)
50 {
51 unsigned int lsize;
52
53 /*
54 * Set PCI cacheline size to that of the last level in the
55 * cache hierarchy.
56 */
57 lsize = cpu_last_level_cache_line_size();
58
59 if (lsize) {
60 pci_dfl_cache_line_size = lsize >> 2;
61
62 pr_debug("PCI: pci_cache_line_size set to %d bytes\n", lsize);
63 }
64
65 return 0;
66 }
67
68 subsys_initcall(pcibios_init);
69
pcibios_device_add(struct pci_dev * dev)70 int pcibios_device_add(struct pci_dev *dev)
71 {
72 int id;
73 struct irq_domain *dom;
74
75 id = pci_domain_nr(dev->bus);
76 dom = irq_find_matching_fwnode(get_pch_msi_handle(id), DOMAIN_BUS_PCI_MSI);
77 dev_set_msi_domain(&dev->dev, dom);
78
79 return 0;
80 }
81
pcibios_alloc_irq(struct pci_dev * dev)82 int pcibios_alloc_irq(struct pci_dev *dev)
83 {
84 if (acpi_disabled)
85 return 0;
86 if (pci_dev_msi_enabled(dev))
87 return 0;
88 return acpi_pci_irq_enable(dev);
89 }
90
pci_fixup_vgadev(struct pci_dev * pdev)91 static void pci_fixup_vgadev(struct pci_dev *pdev)
92 {
93 struct pci_dev *devp = NULL;
94
95 while ((devp = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, devp))) {
96 if (devp->vendor != PCI_VENDOR_ID_LOONGSON) {
97 vga_set_default_device(devp);
98 dev_info(&pdev->dev,
99 "Overriding boot device as %X:%X\n",
100 devp->vendor, devp->device);
101 }
102 }
103 }
104 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev);
105 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev);
106 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC3, pci_fixup_vgadev);
107
108 #define CRTC_NUM_MAX 2
109 #define CRTC_OUTPUT_ENABLE 0x100
110
loongson_gpu_fixup_dma_hang(struct pci_dev * pdev,bool on)111 static void loongson_gpu_fixup_dma_hang(struct pci_dev *pdev, bool on)
112 {
113 u32 i, val, count, crtc_offset, device;
114 void __iomem *crtc_reg, *base, *regbase;
115 static u32 crtc_status[CRTC_NUM_MAX] = { 0 };
116
117 base = pdev->bus->ops->map_bus(pdev->bus, pdev->devfn + 1, 0);
118 device = readw(base + PCI_DEVICE_ID);
119
120 regbase = ioremap(readq(base + PCI_BASE_ADDRESS_0) & ~0xffull, SZ_64K);
121 if (!regbase) {
122 pci_err(pdev, "Failed to ioremap()\n");
123 return;
124 }
125
126 switch (device) {
127 case PCI_DEVICE_ID_LOONGSON_DC2:
128 crtc_reg = regbase + 0x1240;
129 crtc_offset = 0x10;
130 break;
131 case PCI_DEVICE_ID_LOONGSON_DC3:
132 crtc_reg = regbase;
133 crtc_offset = 0x400;
134 break;
135 default:
136 iounmap(regbase);
137 return;
138 }
139
140 for (i = 0; i < CRTC_NUM_MAX; i++, crtc_reg += crtc_offset) {
141 val = readl(crtc_reg);
142
143 if (!on)
144 crtc_status[i] = val;
145
146 /* No need to fixup if the status is off at startup. */
147 if (!(crtc_status[i] & CRTC_OUTPUT_ENABLE))
148 continue;
149
150 if (on)
151 val |= CRTC_OUTPUT_ENABLE;
152 else
153 val &= ~CRTC_OUTPUT_ENABLE;
154
155 mb();
156 writel(val, crtc_reg);
157
158 for (count = 0; count < 40; count++) {
159 val = readl(crtc_reg) & CRTC_OUTPUT_ENABLE;
160 if ((on && val) || (!on && !val))
161 break;
162 udelay(1000);
163 }
164
165 pci_info(pdev, "DMA hang fixup at reg[0x%lx]: 0x%x\n",
166 (unsigned long)crtc_reg & 0xffff, readl(crtc_reg));
167 }
168
169 iounmap(regbase);
170 }
171
pci_fixup_dma_hang_early(struct pci_dev * pdev)172 static void pci_fixup_dma_hang_early(struct pci_dev *pdev)
173 {
174 loongson_gpu_fixup_dma_hang(pdev, false);
175 }
176 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_early);
177 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_early);
178
pci_fixup_dma_hang_final(struct pci_dev * pdev)179 static void pci_fixup_dma_hang_final(struct pci_dev *pdev)
180 {
181 loongson_gpu_fixup_dma_hang(pdev, true);
182 }
183 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_final);
184 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_final);
185