GNU Linux-libre 4.19.286-gnu1
[releases.git] / arch / mips / pci / ops-loongson3.c
1 // SPDX-License-Identifier: GPL-2.0
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 };