Loading...
Note: File does not exist in v6.13.7.
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
16static 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
65static 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
85static 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
113struct pci_ops loongson_pci_ops = {
114 .read = loongson3_pci_pcibios_read,
115 .write = loongson3_pci_pcibios_write
116};