ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / mips / pci / ops-bonito64.c
1 /*
2  * Carsten Langgaard, carstenl@mips.com
3  * Copyright (C) 1999, 2000 MIPS Technologies, Inc.  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  * MIPS boards specific PCI support.
19  */
20 #include <linux/config.h>
21 #include <linux/types.h>
22 #include <linux/pci.h>
23 #include <linux/kernel.h>
24 #include <linux/init.h>
25
26 #include <asm/mips-boards/bonito64.h>
27
28 #define PCI_ACCESS_READ  0
29 #define PCI_ACCESS_WRITE 1
30
31 /*
32  *  PCI configuration cycle AD bus definition
33  */
34 /* Type 0 */
35 #define PCI_CFG_TYPE0_REG_SHF           0
36 #define PCI_CFG_TYPE0_FUNC_SHF          8
37
38 /* Type 1 */
39 #define PCI_CFG_TYPE1_REG_SHF           0
40 #define PCI_CFG_TYPE1_FUNC_SHF          8
41 #define PCI_CFG_TYPE1_DEV_SHF           11
42 #define PCI_CFG_TYPE1_BUS_SHF           16
43
44 static int bonito64_pcibios_config_access(unsigned char access_type,
45                                       struct pci_bus *bus,
46                                       unsigned int devfn, int where,
47                                       u32 * data)
48 {
49         unsigned char busnum = bus->number;
50         u32 dummy;
51         u64 pci_addr;
52
53         /* Algorithmics Bonito64 system controller. */
54
55         if ((busnum == 0) && (PCI_SLOT(devfn) > 21)) {
56                 /* We number bus 0 devices from 0..21 */
57                 return -1;
58         }
59
60 #ifdef CONFIG_MIPS_BOARDS_GEN
61         if ((busnum == 0) && (PCI_SLOT(devfn) == 17)) {
62                 /* MIPS Core boards have Bonito connected as device 17 */
63                 return -1;
64         }
65 #endif
66
67         /* Clear cause register bits */
68         BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR |
69                           BONITO_PCICMD_MTABORT_CLR);
70
71         /*
72          * Setup pattern to be used as PCI "address" for
73          * Type 0 cycle
74          */
75         if (busnum == 0) {
76                 /* IDSEL */
77                 pci_addr = (u64) 1 << (PCI_SLOT(devfn) + 10);
78         } else {
79                 /* Bus number */
80                 pci_addr = busnum << PCI_CFG_TYPE1_BUS_SHF;
81
82                 /* Device number */
83                 pci_addr |=
84                     PCI_SLOT(devfn) << PCI_CFG_TYPE1_DEV_SHF;
85         }
86
87         /* Function (same for Type 0/1) */
88         pci_addr |= PCI_FUNC(devfn) << PCI_CFG_TYPE0_FUNC_SHF;
89
90         /* Register number (same for Type 0/1) */
91         pci_addr |= (where & ~0x3) << PCI_CFG_TYPE0_REG_SHF;
92
93         if (busnum == 0) {
94                 /* Type 0 */
95                 BONITO_PCIMAP_CFG = pci_addr >> 16;
96         } else {
97                 /* Type 1 */
98                 BONITO_PCIMAP_CFG = (pci_addr >> 16) | 0x10000;
99         }
100
101         pci_addr &= 0xffff;
102
103         /* Flush Bonito register block */
104         dummy = BONITO_PCIMAP_CFG;
105         iob();          /* sync */
106
107         /* Perform access */
108         if (access_type == PCI_ACCESS_WRITE) {
109                 *(volatile u32 *) (_pcictrl_bonito_pcicfg + (u32)pci_addr) = *(u32 *) data;
110
111                 /* Wait till done */
112                 while (BONITO_PCIMSTAT & 0xF);
113         } else {
114                 *(u32 *) data = *(volatile u32 *) (_pcictrl_bonito_pcicfg + (u32)pci_addr);
115         }
116
117         /* Detect Master/Target abort */
118         if (BONITO_PCICMD & (BONITO_PCICMD_MABORT_CLR |
119                              BONITO_PCICMD_MTABORT_CLR)) {
120                 /* Error occurred */
121
122                 /* Clear bits */
123                 BONITO_PCICMD |= (BONITO_PCICMD_MABORT_CLR |
124                                   BONITO_PCICMD_MTABORT_CLR);
125
126                 return -1;
127         }
128
129         return 0;
130 }
131
132
133 /*
134  * We can't address 8 and 16 bit words directly.  Instead we have to
135  * read/write a 32bit word and mask/modify the data we actually want.
136  */
137 static int bonito64_pcibios_read(struct pci_bus *bus, unsigned int devfn,
138                              int where, int size, u32 * val)
139 {
140         u32 data = 0;
141
142         if ((size == 2) && (where & 1))
143                 return PCIBIOS_BAD_REGISTER_NUMBER;
144         else if ((size == 4) && (where & 3))
145                 return PCIBIOS_BAD_REGISTER_NUMBER;
146
147         if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
148                                        &data))
149                 return -1;
150
151         if (size == 1)
152                 *val = (data >> ((where & 3) << 3)) & 0xff;
153         else if (size == 2)
154                 *val = (data >> ((where & 3) << 3)) & 0xffff;
155         else
156                 *val = data;
157
158         return PCIBIOS_SUCCESSFUL;
159 }
160
161 static int bonito64_pcibios_write(struct pci_bus *bus, unsigned int devfn,
162                               int where, int size, u32 val)
163 {
164         u32 data = 0;
165
166         if ((size == 2) && (where & 1))
167                 return PCIBIOS_BAD_REGISTER_NUMBER;
168         else if ((size == 4) && (where & 3))
169                 return PCIBIOS_BAD_REGISTER_NUMBER;
170
171         if (size == 4)
172                 data = val;
173         else {
174                 if (bonito64_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
175                                                where, &data))
176                         return -1;
177
178                 if (size == 1)
179                         data = (data & ~(0xff << ((where & 3) << 3))) |
180                                 (val << ((where & 3) << 3));
181                 else if (size == 2)
182                         data = (data & ~(0xffff << ((where & 3) << 3))) |
183                                 (val << ((where & 3) << 3));
184         }
185
186         if (bonito64_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
187                                        &data))
188                 return -1;
189
190         return PCIBIOS_SUCCESSFUL;
191 }
192
193 struct pci_ops bonito64_pci_ops = {
194         .read = bonito64_pcibios_read,
195         .write = bonito64_pcibios_write
196 };