aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pci/ops-vr41xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci/ops-vr41xx.c')
-rw-r--r--arch/mips/pci/ops-vr41xx.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/arch/mips/pci/ops-vr41xx.c b/arch/mips/pci/ops-vr41xx.c
new file mode 100644
index 000000000000..44654605e461
--- /dev/null
+++ b/arch/mips/pci/ops-vr41xx.c
@@ -0,0 +1,126 @@
1/*
2 * ops-vr41xx.c, PCI configuration routines for the PCIU of NEC VR4100 series.
3 *
4 * Copyright (C) 2001-2003 MontaVista Software Inc.
5 * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
6 * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
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 * Changes:
24 * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
25 * - New creation, NEC VR4122 and VR4131 are supported.
26 */
27#include <linux/pci.h>
28#include <linux/types.h>
29
30#include <asm/io.h>
31
32#define PCICONFDREG KSEG1ADDR(0x0f000c14)
33#define PCICONFAREG KSEG1ADDR(0x0f000c18)
34
35static inline int set_pci_configuration_address(unsigned char number,
36 unsigned int devfn, int where)
37{
38 if (number == 0) {
39 /*
40 * Type 0 configuration
41 */
42 if (PCI_SLOT(devfn) < 11 || where > 0xff)
43 return -EINVAL;
44
45 writel((1U << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) |
46 (where & 0xfc), PCICONFAREG);
47 } else {
48 /*
49 * Type 1 configuration
50 */
51 if (where > 0xff)
52 return -EINVAL;
53
54 writel(((uint32_t)number << 16) | ((devfn & 0xff) << 8) |
55 (where & 0xfc) | 1U, PCICONFAREG);
56 }
57
58 return 0;
59}
60
61static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
62 int size, uint32_t *val)
63{
64 uint32_t data;
65
66 *val = 0xffffffffU;
67 if (set_pci_configuration_address(bus->number, devfn, where) < 0)
68 return PCIBIOS_DEVICE_NOT_FOUND;
69
70 data = readl(PCICONFDREG);
71
72 switch (size) {
73 case 1:
74 *val = (data >> ((where & 3) << 3)) & 0xffU;
75 break;
76 case 2:
77 *val = (data >> ((where & 2) << 3)) & 0xffffU;
78 break;
79 case 4:
80 *val = data;
81 break;
82 default:
83 return PCIBIOS_FUNC_NOT_SUPPORTED;
84 }
85
86 return PCIBIOS_SUCCESSFUL;
87}
88
89static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
90 int size, uint32_t val)
91{
92 uint32_t data;
93 int shift;
94
95 if (set_pci_configuration_address(bus->number, devfn, where) < 0)
96 return PCIBIOS_DEVICE_NOT_FOUND;
97
98 data = readl(PCICONFDREG);
99
100 switch (size) {
101 case 1:
102 shift = (where & 3) << 3;
103 data &= ~(0xffU << shift);
104 data |= ((val & 0xffU) << shift);
105 break;
106 case 2:
107 shift = (where & 2) << 3;
108 data &= ~(0xffffU << shift);
109 data |= ((val & 0xffffU) << shift);
110 break;
111 case 4:
112 data = val;
113 break;
114 default:
115 return PCIBIOS_FUNC_NOT_SUPPORTED;
116 }
117
118 writel(data, PCICONFDREG);
119
120 return PCIBIOS_SUCCESSFUL;
121}
122
123struct pci_ops vr41xx_pci_ops = {
124 .read = pci_config_read,
125 .write = pci_config_write,
126};