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