Linux-libre 5.3.12-gnu
[librecmc/linux-libre.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         int function = PCI_FUNC(devfn);
22         int device = PCI_SLOT(devfn);
23         int reg = where & ~3;
24         void *addrp;
25         u64 addr;
26
27         if (where < PCI_CFG_SPACE_SIZE) { /* standard config */
28                 addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
29                 if (busnum == 0) {
30                         if (device > 31)
31                                 return PCIBIOS_DEVICE_NOT_FOUND;
32                         addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE | addr);
33                 } else {
34                         addrp = (void *)TO_UNCAC(HT1LO_PCICFG_BASE_TP1 | addr);
35                 }
36         } else if (where < PCI_CFG_SPACE_EXP_SIZE) {  /* extended config */
37                 struct pci_dev *rootdev;
38
39                 rootdev = pci_get_domain_bus_and_slot(0, 0, 0);
40                 if (!rootdev)
41                         return PCIBIOS_DEVICE_NOT_FOUND;
42
43                 addr = pci_resource_start(rootdev, 3);
44                 if (!addr)
45                         return PCIBIOS_DEVICE_NOT_FOUND;
46
47                 addr |= busnum << 20 | device << 15 | function << 12 | reg;
48                 addrp = (void *)TO_UNCAC(addr);
49         } else {
50                 return PCIBIOS_DEVICE_NOT_FOUND;
51         }
52
53         if (access_type == PCI_ACCESS_WRITE)
54                 writel(*data, addrp);
55         else {
56                 *data = readl(addrp);
57                 if (*data == 0xffffffff) {
58                         *data = -1;
59                         return PCIBIOS_DEVICE_NOT_FOUND;
60                 }
61         }
62         return PCIBIOS_SUCCESSFUL;
63 }
64
65 static int loongson3_pci_pcibios_read(struct pci_bus *bus, unsigned int devfn,
66                                  int where, int size, u32 *val)
67 {
68         u32 data = 0;
69         int ret = loongson3_pci_config_access(PCI_ACCESS_READ,
70                         bus, devfn, where, &data);
71
72         if (ret != PCIBIOS_SUCCESSFUL)
73                 return ret;
74
75         if (size == 1)
76                 *val = (data >> ((where & 3) << 3)) & 0xff;
77         else if (size == 2)
78                 *val = (data >> ((where & 3) << 3)) & 0xffff;
79         else
80                 *val = data;
81
82         return PCIBIOS_SUCCESSFUL;
83 }
84
85 static int loongson3_pci_pcibios_write(struct pci_bus *bus, unsigned int devfn,
86                                   int where, int size, u32 val)
87 {
88         u32 data = 0;
89         int ret;
90
91         if (size == 4)
92                 data = val;
93         else {
94                 ret = loongson3_pci_config_access(PCI_ACCESS_READ,
95                                 bus, devfn, where, &data);
96                 if (ret != PCIBIOS_SUCCESSFUL)
97                         return ret;
98
99                 if (size == 1)
100                         data = (data & ~(0xff << ((where & 3) << 3))) |
101                             (val << ((where & 3) << 3));
102                 else if (size == 2)
103                         data = (data & ~(0xffff << ((where & 3) << 3))) |
104                             (val << ((where & 3) << 3));
105         }
106
107         ret = loongson3_pci_config_access(PCI_ACCESS_WRITE,
108                         bus, devfn, where, &data);
109
110         return ret;
111 }
112
113 struct pci_ops loongson_pci_ops = {
114         .read = loongson3_pci_pcibios_read,
115         .write = loongson3_pci_pcibios_write
116 };