1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc. |
4 | * All rights reserved. |
5 | * Authors: Carsten Langgaard <carstenl@mips.com> |
6 | * Maciej W. Rozycki <macro@mips.com> |
7 | */ |
8 | #include <linux/types.h> |
9 | #include <linux/pci.h> |
10 | #include <linux/kernel.h> |
11 | |
12 | #include <asm/gt64120.h> |
13 | |
14 | #define PCI_ACCESS_READ 0 |
15 | #define PCI_ACCESS_WRITE 1 |
16 | |
17 | /* |
18 | * PCI configuration cycle AD bus definition |
19 | */ |
20 | /* Type 0 */ |
21 | #define PCI_CFG_TYPE0_REG_SHF 0 |
22 | #define PCI_CFG_TYPE0_FUNC_SHF 8 |
23 | |
24 | /* Type 1 */ |
25 | #define PCI_CFG_TYPE1_REG_SHF 0 |
26 | #define PCI_CFG_TYPE1_FUNC_SHF 8 |
27 | #define PCI_CFG_TYPE1_DEV_SHF 11 |
28 | #define PCI_CFG_TYPE1_BUS_SHF 16 |
29 | |
30 | static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type, |
31 | struct pci_bus *bus, unsigned int devfn, int where, u32 * data) |
32 | { |
33 | unsigned char busnum = bus->number; |
34 | u32 intr; |
35 | |
36 | if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0))) |
37 | return -1; /* Because of a bug in the galileo (for slot 31). */ |
38 | |
39 | /* Clear cause register bits */ |
40 | GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | |
41 | GT_INTRCAUSE_TARABORT0_BIT)); |
42 | |
43 | /* Setup address */ |
44 | GT_WRITE(GT_PCI0_CFGADDR_OFS, |
45 | (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) | |
46 | (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | |
47 | ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | |
48 | GT_PCI0_CFGADDR_CONFIGEN_BIT); |
49 | |
50 | if (access_type == PCI_ACCESS_WRITE) { |
51 | if (busnum == 0 && PCI_SLOT(devfn) == 0) { |
52 | /* |
53 | * The Galileo system controller is acting |
54 | * differently than other devices. |
55 | */ |
56 | GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); |
57 | } else |
58 | __GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); |
59 | } else { |
60 | if (busnum == 0 && PCI_SLOT(devfn) == 0) { |
61 | /* |
62 | * The Galileo system controller is acting |
63 | * differently than other devices. |
64 | */ |
65 | *data = GT_READ(GT_PCI0_CFGDATA_OFS); |
66 | } else |
67 | *data = __GT_READ(GT_PCI0_CFGDATA_OFS); |
68 | } |
69 | |
70 | /* Check for master or target abort */ |
71 | intr = GT_READ(GT_INTRCAUSE_OFS); |
72 | |
73 | if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) { |
74 | /* Error occurred */ |
75 | |
76 | /* Clear bits */ |
77 | GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | |
78 | GT_INTRCAUSE_TARABORT0_BIT)); |
79 | |
80 | return -1; |
81 | } |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | |
87 | /* |
88 | * We can't address 8 and 16 bit words directly. Instead we have to |
89 | * read/write a 32bit word and mask/modify the data we actually want. |
90 | */ |
91 | static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn, |
92 | int where, int size, u32 * val) |
93 | { |
94 | u32 data = 0; |
95 | |
96 | if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, |
97 | where, data: &data)) |
98 | return PCIBIOS_DEVICE_NOT_FOUND; |
99 | |
100 | if (size == 1) |
101 | *val = (data >> ((where & 3) << 3)) & 0xff; |
102 | else if (size == 2) |
103 | *val = (data >> ((where & 3) << 3)) & 0xffff; |
104 | else |
105 | *val = data; |
106 | |
107 | return PCIBIOS_SUCCESSFUL; |
108 | } |
109 | |
110 | static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn, |
111 | int where, int size, u32 val) |
112 | { |
113 | u32 data = 0; |
114 | |
115 | if (size == 4) |
116 | data = val; |
117 | else { |
118 | if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, |
119 | devfn, where, data: &data)) |
120 | return PCIBIOS_DEVICE_NOT_FOUND; |
121 | |
122 | if (size == 1) |
123 | data = (data & ~(0xff << ((where & 3) << 3))) | |
124 | (val << ((where & 3) << 3)); |
125 | else if (size == 2) |
126 | data = (data & ~(0xffff << ((where & 3) << 3))) | |
127 | (val << ((where & 3) << 3)); |
128 | } |
129 | |
130 | if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, |
131 | where, data: &data)) |
132 | return PCIBIOS_DEVICE_NOT_FOUND; |
133 | |
134 | return PCIBIOS_SUCCESSFUL; |
135 | } |
136 | |
137 | struct pci_ops gt64xxx_pci0_ops = { |
138 | .read = gt64xxx_pci0_pcibios_read, |
139 | .write = gt64xxx_pci0_pcibios_write |
140 | }; |
141 | |