[MIPS] TXx9: Reorganize code
[linux-2.6.git] / arch / mips / pci / ops-tx4938.c
1 /*
2  * Define the pci_ops for the Toshiba rbtx4938
3  * Copyright (C) 2000-2001 Toshiba Corporation
4  *
5  * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
6  * terms of the GNU General Public License version 2. This program is
7  * licensed "as is" without any warranty of any kind, whether express
8  * or implied.
9  *
10  * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
11  */
12 #include <linux/types.h>
13 #include <linux/pci.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16
17 #include <asm/addrspace.h>
18 #include <asm/txx9/rbtx4938.h>
19
20 /* initialize in setup */
21 struct resource pci_io_resource = {
22         .name   = "pci IO space",
23         .start  = 0,
24         .end    = 0,
25         .flags  = IORESOURCE_IO
26 };
27
28 /* initialize in setup */
29 struct resource pci_mem_resource = {
30         .name   = "pci memory space",
31         .start  = 0,
32         .end    = 0,
33         .flags  = IORESOURCE_MEM
34 };
35
36 struct resource tx4938_pcic1_pci_io_resource = {
37         .name   = "PCI1 IO",
38         .start  = 0,
39         .end    = 0,
40         .flags  = IORESOURCE_IO
41 };
42 struct resource tx4938_pcic1_pci_mem_resource = {
43         .name   = "PCI1 mem",
44         .start  = 0,
45         .end    = 0,
46         .flags  = IORESOURCE_MEM
47 };
48
49 static int mkaddr(int bus, int dev_fn, int where,
50                   struct tx4938_pcic_reg *pcicptr)
51 {
52         if (bus > 0) {
53                 /* Type 1 configuration */
54                 pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) |
55                     ((dev_fn & 0xff) << 0x08) | (where & 0xfc) | 1;
56         } else {
57                 if (dev_fn >= PCI_DEVFN(TX4938_PCIC_MAX_DEVNU, 0))
58                         return -1;
59
60                 /* Type 0 configuration */
61                 pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) |
62                     ((dev_fn & 0xff) << 0x08) | (where & 0xfc);
63         }
64         /* clear M_ABORT and Disable M_ABORT Int. */
65         pcicptr->pcistatus =
66             (pcicptr->pcistatus & 0x0000ffff) |
67             (PCI_STATUS_REC_MASTER_ABORT << 16);
68         pcicptr->pcimask &= ~PCI_STATUS_REC_MASTER_ABORT;
69
70         return 0;
71 }
72
73 static int check_abort(struct tx4938_pcic_reg *pcicptr)
74 {
75         int code = PCIBIOS_SUCCESSFUL;
76         /* wait write cycle completion before checking error status */
77         while (pcicptr->pcicstatus & TX4938_PCIC_PCICSTATUS_IWB)
78                                 ;
79         if (pcicptr->pcistatus & (PCI_STATUS_REC_MASTER_ABORT << 16)) {
80                 pcicptr->pcistatus =
81                     (pcicptr->
82                      pcistatus & 0x0000ffff) | (PCI_STATUS_REC_MASTER_ABORT
83                                                 << 16);
84                 pcicptr->pcimask |= PCI_STATUS_REC_MASTER_ABORT;
85                 code = PCIBIOS_DEVICE_NOT_FOUND;
86         }
87         return code;
88 }
89
90 extern struct pci_controller tx4938_pci_controller[];
91 extern struct tx4938_pcic_reg *get_tx4938_pcicptr(int ch);
92
93 static struct tx4938_pcic_reg *pci_bus_to_pcicptr(struct pci_bus *bus)
94 {
95         struct pci_controller *channel = bus->sysdata;
96         return get_tx4938_pcicptr(channel - &tx4938_pci_controller[0]);
97 }
98
99 static int tx4938_pcibios_read_config(struct pci_bus *bus, unsigned int devfn,
100                                         int where, int size, u32 * val)
101 {
102         int retval, dev, busno, func;
103         struct tx4938_pcic_reg *pcicptr = pci_bus_to_pcicptr(bus);
104         void __iomem *cfgdata =
105                 (void __iomem *)(unsigned long)&pcicptr->g2pcfgdata;
106
107         dev = PCI_SLOT(devfn);
108         func = PCI_FUNC(devfn);
109
110         /* check if the bus is top-level */
111         if (bus->parent != NULL)
112                 busno = bus->number;
113         else {
114                 busno = 0;
115         }
116
117         if (mkaddr(busno, devfn, where, pcicptr))
118                 return -1;
119
120         switch (size) {
121         case 1:
122 #ifdef __BIG_ENDIAN
123                 cfgdata += (where & 3) ^ 3;
124 #else
125                 cfgdata += where & 3;
126 #endif
127                 *val = __raw_readb(cfgdata);
128                 break;
129         case 2:
130 #ifdef __BIG_ENDIAN
131                 cfgdata += (where & 2) ^ 2;
132 #else
133                 cfgdata += where & 2;
134 #endif
135                 *val = __raw_readw(cfgdata);
136                 break;
137         case 4:
138                 *val = __raw_readl(cfgdata);
139                 break;
140         }
141
142         retval = check_abort(pcicptr);
143         if (retval == PCIBIOS_DEVICE_NOT_FOUND)
144                 *val = 0xffffffff;
145
146         return retval;
147 }
148
149 static int tx4938_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, int where,
150                                                 int size, u32 val)
151 {
152         int dev, busno, func;
153         struct tx4938_pcic_reg *pcicptr = pci_bus_to_pcicptr(bus);
154         void __iomem *cfgdata =
155                 (void __iomem *)(unsigned long)&pcicptr->g2pcfgdata;
156
157         busno = bus->number;
158         dev = PCI_SLOT(devfn);
159         func = PCI_FUNC(devfn);
160
161         /* check if the bus is top-level */
162         if (bus->parent != NULL) {
163                 busno = bus->number;
164         } else {
165                 busno = 0;
166         }
167
168         if (mkaddr(busno, devfn, where, pcicptr))
169                 return -1;
170
171         switch (size) {
172         case 1:
173 #ifdef __BIG_ENDIAN
174                 cfgdata += (where & 3) ^ 3;
175 #else
176                 cfgdata += where & 3;
177 #endif
178                 __raw_writeb(val, cfgdata);
179                 break;
180         case 2:
181 #ifdef __BIG_ENDIAN
182                 cfgdata += (where & 2) ^ 2;
183 #else
184                 cfgdata += where & 2;
185 #endif
186                 __raw_writew(val, cfgdata);
187                 break;
188         case 4:
189                 __raw_writel(val, cfgdata);
190                 break;
191         }
192
193         return check_abort(pcicptr);
194 }
195
196 struct pci_ops tx4938_pci_ops = {
197         tx4938_pcibios_read_config,
198         tx4938_pcibios_write_config
199 };
200
201 struct pci_controller tx4938_pci_controller[] = {
202         /* h/w only supports devices 0x00 to 0x14 */
203         {
204                 .pci_ops        = &tx4938_pci_ops,
205                 .io_resource    = &pci_io_resource,
206                 .mem_resource   = &pci_mem_resource,
207         },
208         /* h/w only supports devices 0x00 to 0x14 */
209         {
210                 .pci_ops        = &tx4938_pci_ops,
211                 .io_resource    = &tx4938_pcic1_pci_io_resource,
212                 .mem_resource   = &tx4938_pcic1_pci_mem_resource,
213         }
214 };