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