ee1647121e390248882fce30f477c8a5a940aa00
[openwrt/openwrt.git] / target / linux / brcm63xx / files / arch / mips / pci / ops-bcm96348.c
1 /*
2 <:copyright-gpl
3 Copyright 2002 Broadcom Corp. All Rights Reserved.
4
5 This program is free software; you can distribute it and/or modify it
6 under the terms of the GNU General Public License (Version 2) as
7 published by the Free Software Foundation.
8
9 This program is distributed in the hope it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17 :>
18 */
19 #include <linux/types.h>
20 #include <linux/pci.h>
21 #include <linux/kernel.h>
22 #include <linux/init.h>
23 #include <asm/addrspace.h>
24
25 #include <bcm_intr.h>
26 #include <bcm_map_part.h>
27 #include <6348_intr.h>
28 #include <6348_map_part.h>
29 #include <bcmpci.h>
30
31 #include <linux/delay.h>
32
33 #if defined(CONFIG_USB)
34 #if 0
35 #define DPRINT(x...) printk(x)
36 #else
37 #define DPRINT(x...)
38 #endif
39
40 static int
41 pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size);
42 static int
43 pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size);
44
45 static bool usb_mem_size_rd = FALSE;
46 static uint32 usb_mem_base = 0;
47 static uint32 usb_cfg_space_cmd_reg = 0;
48 #endif
49 static bool pci_mem_size_rd = FALSE;
50
51 static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
52
53 static void mpi_SetupPciConfigAccess(uint32 addr)
54 {
55 mpi->l2pcfgctl = (DIR_CFG_SEL | DIR_CFG_USEREG | addr) & ~CONFIG_TYPE;
56 }
57
58 static void mpi_ClearPciConfigAccess(void)
59 {
60 mpi->l2pcfgctl = 0x00000000;
61 }
62
63 #if defined(CONFIG_USB)
64 /* --------------------------------------------------------------------------
65 Name: pci63xx_int_write
66 Abstract: PCI Config write on internal device(s)
67 -------------------------------------------------------------------------- */
68 static int
69 pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size)
70 {
71 if (PCI_SLOT(devfn) != USB_HOST_SLOT) {
72 return PCIBIOS_SUCCESSFUL;
73 }
74
75 switch (size) {
76 case 1:
77 DPRINT("W => Slot: %d Where: %2X Len: %d Data: %02X\n",
78 PCI_SLOT(devfn), where, size, *value);
79 break;
80 case 2:
81 DPRINT("W => Slot: %d Where: %2X Len: %d Data: %04X\n",
82 PCI_SLOT(devfn), where, size, *value);
83 switch (where) {
84 case PCI_COMMAND:
85 usb_cfg_space_cmd_reg = *value;
86 break;
87 default:
88 break;
89 }
90 break;
91 case 4:
92 DPRINT("W => Slot: %d Where: %2X Len: %d Data: %08lX\n",
93 PCI_SLOT(devfn), where, size, *value);
94 switch (where) {
95 case PCI_BASE_ADDRESS_0:
96 if (*value == 0xffffffff) {
97 usb_mem_size_rd = TRUE;
98 } else {
99 usb_mem_base = *value;
100 }
101 break;
102 default:
103 break;
104 }
105 break;
106 default:
107 break;
108 }
109
110 return PCIBIOS_SUCCESSFUL;
111 }
112
113 /* --------------------------------------------------------------------------
114 Name: pci63xx_int_read
115 Abstract: PCI Config read on internal device(s)
116 -------------------------------------------------------------------------- */
117 static int
118 pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size)
119 {
120 uint32 retValue = 0xFFFFFFFF;
121
122 if (PCI_SLOT(devfn) != USB_HOST_SLOT) {
123 return PCIBIOS_SUCCESSFUL;
124 }
125
126 // For now, this is specific to the USB Host controller. We can
127 // make it more general if we have to...
128 // Emulate PCI Config accesses
129 switch (where) {
130 case PCI_VENDOR_ID:
131 case PCI_DEVICE_ID:
132 retValue = PCI_VENDOR_ID_BROADCOM | 0x63000000;
133 break;
134 case PCI_COMMAND:
135 case PCI_STATUS:
136 retValue = (0x0006 << 16) | usb_cfg_space_cmd_reg;
137 break;
138 case PCI_CLASS_REVISION:
139 case PCI_CLASS_DEVICE:
140 retValue = (PCI_CLASS_SERIAL_USB << 16) | (0x10 << 8) | 0x01;
141 break;
142 case PCI_BASE_ADDRESS_0:
143 if (usb_mem_size_rd) {
144 retValue = USB_BAR0_MEM_SIZE;
145 } else {
146 if (usb_mem_base != 0)
147 retValue = usb_mem_base;
148 else
149 retValue = USB_HOST_BASE;
150 }
151 usb_mem_size_rd = FALSE;
152 break;
153 case PCI_CACHE_LINE_SIZE:
154 case PCI_LATENCY_TIMER:
155 retValue = 0;
156 break;
157 case PCI_HEADER_TYPE:
158 retValue = PCI_HEADER_TYPE_NORMAL;
159 break;
160 case PCI_SUBSYSTEM_VENDOR_ID:
161 retValue = PCI_VENDOR_ID_BROADCOM;
162 break;
163 case PCI_SUBSYSTEM_ID:
164 retValue = 0x6300;
165 break;
166 case PCI_INTERRUPT_LINE:
167 retValue = INTERRUPT_ID_USBH;
168 break;
169 default:
170 break;
171 }
172
173 switch (size) {
174 case 1:
175 *value = (retValue >> ((where & 3) << 3)) & 0xff;
176 DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %02X\n",
177 PCI_SLOT(devfn), where, size, *value);
178 break;
179 case 2:
180 *value = (retValue >> ((where & 3) << 3)) & 0xffff;
181 DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %04X\n",
182 PCI_SLOT(devfn), where, size, *value);
183 break;
184 case 4:
185 *value = retValue;
186 DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %08lX\n",
187 PCI_SLOT(devfn), where, size, *value);
188 break;
189 default:
190 break;
191 }
192
193 return PCIBIOS_SUCCESSFUL;
194 }
195 #endif
196
197 static int bcm96348_pcibios_read(struct pci_bus *bus, unsigned int devfn,
198 int where, int size, u32 * val)
199 {
200 volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1);
201 uint32 data;
202
203 #if defined(CONFIG_USB)
204 if (PCI_SLOT(devfn) == USB_HOST_SLOT)
205 return pci63xx_int_read(devfn, where, val, size);
206 #endif
207
208 mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where));
209 data = *(uint32 *)ioBase;
210 switch(size) {
211 case 1:
212 *val = (data >> ((where & 3) << 3)) & 0xff;
213 break;
214 case 2:
215 *val = (data >> ((where & 3) << 3)) & 0xffff;
216 break;
217 case 4:
218 *val = data;
219 /* Special case for reading PCI device range */
220 if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) {
221 if (pci_mem_size_rd) {
222 /* bcm6348 PCI memory window minimum size is 64K */
223 *val &= PCI_SIZE_64K;
224 }
225 }
226 break;
227 default:
228 break;
229 }
230 pci_mem_size_rd = FALSE;
231 mpi_ClearPciConfigAccess();
232
233 return PCIBIOS_SUCCESSFUL;
234 }
235
236 static int bcm96348_pcibios_write(struct pci_bus *bus, unsigned int devfn,
237 int where, int size, u32 val)
238 {
239 volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1);
240 uint32 data;
241
242 #if defined(CONFIG_USB)
243 if (PCI_SLOT(devfn) == USB_HOST_SLOT)
244 return pci63xx_int_write(devfn, where, &val, size);
245 #endif
246 mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where));
247 data = *(uint32 *)ioBase;
248 switch(size) {
249 case 1:
250 data = (data & ~(0xff << ((where & 3) << 3))) |
251 (val << ((where & 3) << 3));
252 break;
253 case 2:
254 data = (data & ~(0xffff << ((where & 3) << 3))) |
255 (val << ((where & 3) << 3));
256 break;
257 case 4:
258 data = val;
259 /* Special case for reading PCI device range */
260 if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) {
261 if (val == 0xffffffff)
262 pci_mem_size_rd = TRUE;
263 }
264 break;
265 default:
266 break;
267 }
268 *(uint32 *)ioBase = data;
269 udelay(500);
270 mpi_ClearPciConfigAccess();
271
272 return PCIBIOS_SUCCESSFUL;
273 }
274
275 struct pci_ops bcm96348_pci_ops = {
276 .read = bcm96348_pcibios_read,
277 .write = bcm96348_pcibios_write
278 };