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 #include <linux/types.h>
19 #include <linux/pci.h>
20 #include <linux/kernel.h>
21 #include <linux/init.h>
22 
23 #include <asm/mips-boards/msc01_pci.h>
24 
25 #define PCI_ACCESS_READ  0
26 #define PCI_ACCESS_WRITE 1
27 
28 /*
29  *  PCI configuration cycle AD bus definition
30  */
31 /* Type 0 */
32 #define PCI_CFG_TYPE0_REG_SHF           0
33 #define PCI_CFG_TYPE0_FUNC_SHF          8
34 
35 /* Type 1 */
36 #define PCI_CFG_TYPE1_REG_SHF           0
37 #define PCI_CFG_TYPE1_FUNC_SHF          8
38 #define PCI_CFG_TYPE1_DEV_SHF           11
39 #define PCI_CFG_TYPE1_BUS_SHF           16
40 
msc_config_access(unsigned char access_type,struct pci_dev * dev,unsigned char where,u32 * data)41 static int msc_config_access(unsigned char access_type,
42 	struct pci_dev *dev, unsigned char where, u32 *data)
43 {
44 	unsigned char bus = dev->bus->number;
45 	unsigned char dev_fn = dev->devfn;
46 	unsigned char type;
47 	u32 intr, dummy;
48 	u64 pci_addr;
49 
50 	if ((bus == 0) && (PCI_SLOT(dev_fn) == 0))
51 	        return -1;
52 
53 	/* Clear status register bits. */
54 	MSC_WRITE(MSC01_PCI_INTSTAT,
55 		  (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT));
56 
57 	/* Setup address */
58 	if (bus == 0)
59 		type = 0;  /* Type 0 */
60 	else
61 		type = 1;  /* Type 1 */
62 
63 	MSC_WRITE(MSC01_PCI_CFGADDR,
64 		  ((bus              << MSC01_PCI_CFGADDR_BNUM_SHF) |
65 		   (PCI_SLOT(dev_fn) << MSC01_PCI_CFGADDR_DNUM_SHF) |
66 		   (PCI_FUNC(dev_fn) << MSC01_PCI_CFGADDR_FNUM_SHF) |
67 		   ((where /4 )      << MSC01_PCI_CFGADDR_RNUM_SHF) |
68 		   (type)));
69 
70 	/* Perform access */
71 	if (access_type == PCI_ACCESS_WRITE) {
72 	        MSC_WRITE(MSC01_PCI_CFGDATA, *data);
73 	} else {
74 		MSC_READ(MSC01_PCI_CFGDATA, *data);
75 	}
76 
77 	/* Detect Master/Target abort */
78 	MSC_READ(MSC01_PCI_INTSTAT, intr);
79 	if (intr & (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT)) {
80 	        /* Error occurred */
81 
82 	        /* Clear bits */
83 		MSC_READ(MSC01_PCI_INTSTAT, intr);
84 		MSC_WRITE(MSC01_PCI_INTSTAT,
85 			  (MSC01_PCI_INTCFG_MA_BIT |
86 			   MSC01_PCI_INTCFG_TA_BIT));
87 
88 		return -1;
89 	}
90 
91 	return 0;
92 }
93 
94 
95 /*
96  * We can't address 8 and 16 bit words directly.  Instead we have to
97  * read/write a 32bit word and mask/modify the data we actually want.
98  */
msc_read_config_byte(struct pci_dev * dev,int where,u8 * val)99 static int msc_read_config_byte (struct pci_dev *dev, int where,
100 	u8 *val)
101 {
102 	u32 data = 0;
103 
104 	if (msc_config_access(PCI_ACCESS_READ, dev, where, &data))
105 		return -1;
106 
107 	*val = (data >> ((where & 3) << 3)) & 0xff;
108 
109 	return PCIBIOS_SUCCESSFUL;
110 }
111 
msc_read_config_word(struct pci_dev * dev,int where,u16 * val)112 static int msc_read_config_word (struct pci_dev *dev, int where,
113 	u16 *val)
114 {
115 	u32 data = 0;
116 
117 	if (where & 1)
118 		return PCIBIOS_BAD_REGISTER_NUMBER;
119 
120 	if (msc_config_access(PCI_ACCESS_READ, dev, where, &data))
121 	       return -1;
122 
123 	*val = (data >> ((where & 3) << 3)) & 0xffff;
124 
125 	return PCIBIOS_SUCCESSFUL;
126 }
127 
msc_read_config_dword(struct pci_dev * dev,int where,u32 * val)128 static int msc_read_config_dword (struct pci_dev *dev, int where,
129 	u32 *val)
130 {
131 	u32 data = 0;
132 
133 	if (where & 3)
134 		return PCIBIOS_BAD_REGISTER_NUMBER;
135 
136 	if (msc_config_access(PCI_ACCESS_READ, dev, where, &data))
137 		return -1;
138 
139 	*val = data;
140 
141 	return PCIBIOS_SUCCESSFUL;
142 }
143 
msc_write_config_byte(struct pci_dev * dev,int where,u8 val)144 static int msc_write_config_byte (struct pci_dev *dev, int where,
145 	u8 val)
146 {
147 	u32 data = 0;
148 
149 	if (msc_config_access(PCI_ACCESS_READ, dev, where, &data))
150 		return -1;
151 
152 	data = (data & ~(0xff << ((where & 3) << 3))) |
153 	       (val << ((where & 3) << 3));
154 
155 	if (msc_config_access(PCI_ACCESS_WRITE, dev, where, &data))
156 		return -1;
157 
158 	return PCIBIOS_SUCCESSFUL;
159 }
160 
msc_write_config_word(struct pci_dev * dev,int where,u16 val)161 static int msc_write_config_word (struct pci_dev *dev, int where,
162 	u16 val)
163 {
164         u32 data = 0;
165 
166 	if (where & 1)
167 		return PCIBIOS_BAD_REGISTER_NUMBER;
168 
169         if (msc_config_access(PCI_ACCESS_READ, dev, where, &data))
170 	       return -1;
171 
172 	data = (data & ~(0xffff << ((where & 3) << 3))) |
173 	       (val << ((where & 3) << 3));
174 
175 	if (msc_config_access(PCI_ACCESS_WRITE, dev, where, &data))
176 	       return -1;
177 
178 
179 	return PCIBIOS_SUCCESSFUL;
180 }
181 
msc_write_config_dword(struct pci_dev * dev,int where,u32 val)182 static int msc_write_config_dword(struct pci_dev *dev, int where,
183 	u32 val)
184 {
185 	if (where & 3)
186 		return PCIBIOS_BAD_REGISTER_NUMBER;
187 
188 	if (msc_config_access(PCI_ACCESS_WRITE, dev, where, &val))
189 	       return -1;
190 
191 	return PCIBIOS_SUCCESSFUL;
192 }
193 
194 struct pci_ops msc_pci_ops = {
195 	msc_read_config_byte,
196         msc_read_config_word,
197 	msc_read_config_dword,
198 	msc_write_config_byte,
199 	msc_write_config_word,
200 	msc_write_config_dword
201 };
202