Merge branch 'x86-kbuild-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / arch / mips / pci / ops-emma2rh.c
1 /*
2  *  Copyright (C) NEC Electronics Corporation 2004-2006
3  *
4  *  This file is based on the arch/mips/pci/ops-vr41xx.c
5  *
6  *      Copyright 2001 MontaVista Software Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <linux/pci.h>
24 #include <linux/kernel.h>
25 #include <linux/types.h>
26
27 #include <asm/addrspace.h>
28 #include <asm/debug.h>
29
30 #include <asm/emma/emma2rh.h>
31
32 #define RTABORT (0x1<<9)
33 #define RMABORT (0x1<<10)
34 #define EMMA2RH_PCI_SLOT_NUM 9  /* 0000:09.0 is final PCI device */
35
36 /*
37  * access config space
38  */
39
40 static int check_args(struct pci_bus *bus, u32 devfn, u32 * bus_num)
41 {
42         /* check if the bus is top-level */
43         if (bus->parent != NULL) {
44                 *bus_num = bus->number;
45                 db_assert(bus_num != NULL);
46         } else
47                 *bus_num = 0;
48
49         if (*bus_num == 0) {
50                 /* Type 0 */
51                 if (PCI_SLOT(devfn) >= 10)
52                         return PCIBIOS_DEVICE_NOT_FOUND;
53         } else {
54                 /* Type 1 */
55                 if ((*bus_num >= 64) || (PCI_SLOT(devfn) >= 16))
56                         return PCIBIOS_DEVICE_NOT_FOUND;
57         }
58         return 0;
59 }
60
61 static inline int set_pci_configuration_address(unsigned char bus_num,
62                                                 unsigned int devfn, int where)
63 {
64         u32 config_win0;
65
66         emma2rh_out32(EMMA2RH_PCI_INT, ~RMABORT);
67         if (bus_num == 0)
68                 /*
69                  * Type 0 configuration
70                  */
71                 config_win0 = (1 << (22 + PCI_SLOT(devfn))) | (5 << 9);
72         else
73                 /*
74                  * Type 1 configuration
75                  */
76                 config_win0 = (bus_num << 26) | (PCI_SLOT(devfn) << 22) |
77                     (1 << 15) | (5 << 9);
78
79         emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, config_win0);
80
81         return 0;
82 }
83
84 static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
85                            int size, uint32_t * val)
86 {
87         u32 bus_num;
88         u32 base = KSEG1ADDR(EMMA2RH_PCI_CONFIG_BASE);
89         u32 backup_win0;
90         u32 data;
91
92         *val = 0xffffffffU;
93
94         if (check_args(bus, devfn, &bus_num) == PCIBIOS_DEVICE_NOT_FOUND)
95                 return PCIBIOS_DEVICE_NOT_FOUND;
96
97         backup_win0 = emma2rh_in32(EMMA2RH_PCI_IWIN0_CTR);
98
99         if (set_pci_configuration_address(bus_num, devfn, where) < 0)
100                 return PCIBIOS_DEVICE_NOT_FOUND;
101
102         data =
103             *(volatile u32 *)(base + (PCI_FUNC(devfn) << 8) +
104                               (where & 0xfffffffc));
105
106         switch (size) {
107         case 1:
108                 *val = (data >> ((where & 3) << 3)) & 0xffU;
109                 break;
110         case 2:
111                 *val = (data >> ((where & 2) << 3)) & 0xffffU;
112                 break;
113         case 4:
114                 *val = data;
115                 break;
116         default:
117                 emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0);
118                 return PCIBIOS_FUNC_NOT_SUPPORTED;
119         }
120
121         emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0);
122
123         if (emma2rh_in32(EMMA2RH_PCI_INT) & RMABORT)
124                 return PCIBIOS_DEVICE_NOT_FOUND;
125
126         return PCIBIOS_SUCCESSFUL;
127 }
128
129 static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
130                             int size, u32 val)
131 {
132         u32 bus_num;
133         u32 base = KSEG1ADDR(EMMA2RH_PCI_CONFIG_BASE);
134         u32 backup_win0;
135         u32 data;
136         int shift;
137
138         if (check_args(bus, devfn, &bus_num) == PCIBIOS_DEVICE_NOT_FOUND)
139                 return PCIBIOS_DEVICE_NOT_FOUND;
140
141         backup_win0 = emma2rh_in32(EMMA2RH_PCI_IWIN0_CTR);
142
143         if (set_pci_configuration_address(bus_num, devfn, where) < 0)
144                 return PCIBIOS_DEVICE_NOT_FOUND;
145
146         /* read modify write */
147         data =
148             *(volatile u32 *)(base + (PCI_FUNC(devfn) << 8) +
149                               (where & 0xfffffffc));
150
151         switch (size) {
152         case 1:
153                 shift = (where & 3) << 3;
154                 data &= ~(0xffU << shift);
155                 data |= ((val & 0xffU) << shift);
156                 break;
157         case 2:
158                 shift = (where & 2) << 3;
159                 data &= ~(0xffffU << shift);
160                 data |= ((val & 0xffffU) << shift);
161                 break;
162         case 4:
163                 data = val;
164                 break;
165         default:
166                 emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0);
167                 return PCIBIOS_FUNC_NOT_SUPPORTED;
168         }
169         *(volatile u32 *)(base + (PCI_FUNC(devfn) << 8) +
170                           (where & 0xfffffffc)) = data;
171
172         emma2rh_out32(EMMA2RH_PCI_IWIN0_CTR, backup_win0);
173         if (emma2rh_in32(EMMA2RH_PCI_INT) & RMABORT)
174                 return PCIBIOS_DEVICE_NOT_FOUND;
175
176         return PCIBIOS_SUCCESSFUL;
177 }
178
179 struct pci_ops emma2rh_pci_ops = {
180         .read = pci_config_read,
181         .write = pci_config_write,
182 };