1/*
2 *
3 *  BRIEF MODULE DESCRIPTION
4 *
5 *  2.6 port, Embedded Alley Solutions, Inc
6 *
7 *  Based on:
8 *  Author: source@mvista.com
9 *
10 *  This program is free software; you can distribute it and/or modify it
11 *  under the terms of the GNU General Public License (Version 2) as
12 *  published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope it will be useful, but WITHOUT
15 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 *  for more details.
18 *
19 *  You should have received a copy of the GNU General Public License along
20 *  with this program; if not, write to the Free Software Foundation, Inc.,
21 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 */
23#include <linux/types.h>
24#include <linux/pci.h>
25#include <linux/kernel.h>
26#include <linux/init.h>
27#include <linux/vmalloc.h>
28#include <linux/delay.h>
29
30#include <asm/mach-pnx8550/pci.h>
31#include <asm/mach-pnx8550/glb.h>
32#include <asm/debug.h>
33
34
35static inline void clear_status(void)
36{
37	unsigned long pci_stat;
38
39	pci_stat = inl(PCI_BASE | PCI_GPPM_STATUS);
40	outl(pci_stat, PCI_BASE | PCI_GPPM_ICLR);
41}
42
43static inline unsigned int
44calc_cfg_addr(struct pci_bus *bus, unsigned int devfn, int where)
45{
46	unsigned int addr;
47
48	addr = ((bus->number > 0) ? (((bus->number & 0xff) << PCI_CFG_BUS_SHIFT) | 1) : 0);
49	addr |= ((devfn & 0xff) << PCI_CFG_FUNC_SHIFT) | (where & 0xfc);
50
51	return addr;
52}
53
54static int
55config_access(unsigned int pci_cmd, struct pci_bus *bus, unsigned int devfn, int where, unsigned int pci_mode, unsigned int *val)
56{
57	unsigned int flags;
58	unsigned long loops = 0;
59	unsigned long ioaddr = calc_cfg_addr(bus, devfn, where);
60
61	local_irq_save(flags);
62	/*Clear pending interrupt status */
63	if (inl(PCI_BASE | PCI_GPPM_STATUS)) {
64		clear_status();
65		while (!(inl(PCI_BASE | PCI_GPPM_STATUS) == 0)) ;
66	}
67
68	outl(ioaddr, PCI_BASE | PCI_GPPM_ADDR);
69
70	if ((pci_cmd == PCI_CMD_IOW) || (pci_cmd == PCI_CMD_CONFIG_WRITE))
71		outl(*val, PCI_BASE | PCI_GPPM_WDAT);
72
73	outl(INIT_PCI_CYCLE | pci_cmd | (pci_mode & PCI_BYTE_ENABLE_MASK),
74	     PCI_BASE | PCI_GPPM_CTRL);
75
76	loops =
77	    ((loops_per_jiffy *
78	      PCI_IO_JIFFIES_TIMEOUT) >> (PCI_IO_JIFFIES_SHIFT));
79	while (1) {
80		if (inl(PCI_BASE | PCI_GPPM_STATUS) & GPPM_DONE) {
81			if ((pci_cmd == PCI_CMD_IOR) ||
82			    (pci_cmd == PCI_CMD_CONFIG_READ))
83				*val = inl(PCI_BASE | PCI_GPPM_RDAT);
84			clear_status();
85			local_irq_restore(flags);
86			return PCIBIOS_SUCCESSFUL;
87		} else if (inl(PCI_BASE | PCI_GPPM_STATUS) & GPPM_R_MABORT) {
88			break;
89		}
90
91		loops--;
92		if (loops == 0) {
93			printk("%s : Arbiter Locked.\n", __FUNCTION__);
94		}
95	}
96
97	clear_status();
98	if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_IOW)) {
99		printk("%s timeout (GPPM_CTRL=%X) ioaddr %lX pci_cmd %X\n",
100		       __FUNCTION__, inl(PCI_BASE | PCI_GPPM_CTRL), ioaddr,
101		       pci_cmd);
102	}
103
104	if ((pci_cmd == PCI_CMD_IOR) || (pci_cmd == PCI_CMD_CONFIG_READ))
105		*val = 0xffffffff;
106	local_irq_restore(flags);
107	return PCIBIOS_DEVICE_NOT_FOUND;
108}
109
110/*
111 * We can't address 8 and 16 bit words directly.  Instead we have to
112 * read/write a 32bit word and mask/modify the data we actually want.
113 */
114static int
115read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val)
116{
117	unsigned int data = 0;
118	int err;
119
120	if (bus == 0)
121		return -1;
122
123	err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, ~(1 << (where & 3)), &data);
124	switch (where & 0x03) {
125	case 0:
126		*val = (unsigned char)(data & 0x000000ff);
127		break;
128	case 1:
129		*val = (unsigned char)((data & 0x0000ff00) >> 8);
130		break;
131	case 2:
132		*val = (unsigned char)((data & 0x00ff0000) >> 16);
133		break;
134	case 3:
135		*val = (unsigned char)((data & 0xff000000) >> 24);
136		break;
137	}
138
139	return err;
140}
141
142static int
143read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val)
144{
145	unsigned int data = 0;
146	int err;
147
148	if (bus == 0)
149		return -1;
150
151	if (where & 0x01)
152		return PCIBIOS_BAD_REGISTER_NUMBER;
153
154	err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, ~(3 << (where & 3)), &data);
155	switch (where & 0x02) {
156	case 0:
157		*val = (unsigned short)(data & 0x0000ffff);
158		break;
159	case 2:
160		*val = (unsigned short)((data & 0xffff0000) >> 16);
161		break;
162	}
163
164	return err;
165}
166
167static int
168read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val)
169{
170	int err;
171	if (bus == 0)
172		return -1;
173
174	if (where & 0x03)
175		return PCIBIOS_BAD_REGISTER_NUMBER;
176
177	err = config_access(PCI_CMD_CONFIG_READ, bus, devfn, where, 0, val);
178
179	return err;
180}
181
182static int
183write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val)
184{
185	unsigned int data = (unsigned int)val;
186	int err;
187
188	if (bus == 0)
189		return -1;
190
191	switch (where & 0x03) {
192	case 1:
193		data = (data << 8);
194		break;
195	case 2:
196		data = (data << 16);
197		break;
198	case 3:
199		data = (data << 24);
200		break;
201	default:
202		break;
203	}
204
205	err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, ~(1 << (where & 3)), &data);
206
207	return err;
208}
209
210static int
211write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val)
212{
213	unsigned int data = (unsigned int)val;
214	int err;
215
216	if (bus == 0)
217		return -1;
218
219	if (where & 0x01)
220		return PCIBIOS_BAD_REGISTER_NUMBER;
221
222	switch (where & 0x02) {
223	case 2:
224		data = (data << 16);
225		break;
226	default:
227		break;
228	}
229	err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, ~(3 << (where & 3)), &data);
230
231	return err;
232}
233
234static int
235write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val)
236{
237	int err;
238	if (bus == 0)
239		return -1;
240
241	if (where & 0x03)
242		return PCIBIOS_BAD_REGISTER_NUMBER;
243
244	err = config_access(PCI_CMD_CONFIG_WRITE, bus, devfn, where, 0, &val);
245
246	return err;
247}
248
249static int config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val)
250{
251	switch (size) {
252	case 1: {
253			u8 _val;
254			int rc = read_config_byte(bus, devfn, where, &_val);
255			*val = _val;
256			return rc;
257		}
258       case 2: {
259			u16 _val;
260			int rc = read_config_word(bus, devfn, where, &_val);
261			*val = _val;
262			return rc;
263		}
264	default:
265		return read_config_dword(bus, devfn, where, val);
266	}
267}
268
269static int config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val)
270{
271	switch (size) {
272	case 1:
273		return write_config_byte(bus, devfn, where, (u8) val);
274	case 2:
275		return write_config_word(bus, devfn, where, (u16) val);
276	default:
277		return write_config_dword(bus, devfn, where, val);
278	}
279}
280
281struct pci_ops pnx8550_pci_ops = {
282	config_read,
283	config_write
284};
285