]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
c7d3555a HC |
2 | #include <linux/types.h> |
3 | #include <linux/pci.h> | |
4 | #include <linux/kernel.h> | |
5 | ||
6 | #include <asm/mips-boards/bonito64.h> | |
7 | ||
8 | #include <loongson.h> | |
9 | ||
10 | #define PCI_ACCESS_READ 0 | |
11 | #define PCI_ACCESS_WRITE 1 | |
12 | ||
13 | #define HT1LO_PCICFG_BASE 0x1a000000 | |
14 | #define HT1LO_PCICFG_BASE_TP1 0x1b000000 | |
15 | ||
16 | static int loongson3_pci_config_access(unsigned char access_type, | |
17 | struct pci_bus *bus, unsigned int devfn, | |
18 | int where, u32 *data) | |
19 | { | |
20 | unsigned char busnum = bus->number; | |
21 | u_int64_t addr, type; | |
22 | void *addrp; | |
23 | int device = PCI_SLOT(devfn); | |
24 | int function = PCI_FUNC(devfn); | |
25 | int reg = where & ~3; | |
26 | ||
27 | addr = (busnum << 16) | (device << 11) | (function << 8) | reg; | |
28 | if (busnum == 0) { | |
29 | if (device > 31) | |
30 | return PCIBIOS_DEVICE_NOT_FOUND; | |
31 | addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE) | (addr & 0xffff)); | |
32 | type = 0; | |
33 | ||
34 | } else { | |
35 | addrp = (void *)(TO_UNCAC(HT1LO_PCICFG_BASE_TP1) | (addr)); | |
36 | type = 0x10000; | |
37 | } | |
38 | ||
39 | if (access_type == PCI_ACCESS_WRITE) | |
40 | writel(*data, addrp); | |
41 | else { | |
42 | *data = readl(addrp); | |
43 | if (*data == 0xffffffff) { | |
44 | *data = -1; | |
45 | return PCIBIOS_DEVICE_NOT_FOUND; | |
46 | } | |
47 | } | |
48 | return PCIBIOS_SUCCESSFUL; | |
49 | } | |
50 | ||
51 | static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn, | |
52 | int where, int size, u32 *val) | |
53 | { | |
54 | u32 data = 0; | |
55 | int ret = loongson3_pci_config_access(PCI_ACCESS_READ, | |
56 | bus, devfn, where, &data); | |
57 | ||
58 | if (ret != PCIBIOS_SUCCESSFUL) | |
59 | return ret; | |
60 | ||
61 | if (size == 1) | |
62 | *val = (data >> ((where & 3) << 3)) & 0xff; | |
63 | else if (size == 2) | |
64 | *val = (data >> ((where & 3) << 3)) & 0xffff; | |
65 | else | |
66 | *val = data; | |
67 | ||
68 | return PCIBIOS_SUCCESSFUL; | |
69 | } | |
70 | ||
71 | static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn, | |
72 | int where, int size, u32 val) | |
73 | { | |
74 | u32 data = 0; | |
75 | int ret; | |
76 | ||
77 | if (size == 4) | |
78 | data = val; | |
79 | else { | |
80 | ret = loongson3_pci_config_access(PCI_ACCESS_READ, | |
81 | bus, devfn, where, &data); | |
82 | if (ret != PCIBIOS_SUCCESSFUL) | |
83 | return ret; | |
84 | ||
85 | if (size == 1) | |
86 | data = (data & ~(0xff << ((where & 3) << 3))) | | |
87 | (val << ((where & 3) << 3)); | |
88 | else if (size == 2) | |
89 | data = (data & ~(0xffff << ((where & 3) << 3))) | | |
90 | (val << ((where & 3) << 3)); | |
91 | } | |
92 | ||
93 | ret = loongson3_pci_config_access(PCI_ACCESS_WRITE, | |
94 | bus, devfn, where, &data); | |
95 | ||
96 | return ret; | |
97 | } | |
98 | ||
99 | struct pci_ops loongson_pci_ops = { | |
100 | .read = loongson3_pci_pcibios_read, | |
101 | .write = loongson3_pci_pcibios_write | |
102 | }; |