Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
70342287 | 2 | * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. |
1da177e4 LT |
3 | * All rights reserved. |
4 | * Authors: Carsten Langgaard <carstenl@mips.com> | |
70342287 | 5 | * Maciej W. Rozycki <macro@mips.com> |
1da177e4 LT |
6 | * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org) |
7 | * | |
8 | * This program is free software; you can distribute it and/or modify it | |
9 | * under the terms of the GNU General Public License (Version 2) as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope it will be useful, but WITHOUT | |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | * for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along | |
18 | * with this program; if not, write to the Free Software Foundation, Inc., | |
19 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | |
20 | * | |
21 | * MIPS boards specific PCI support. | |
22 | * | |
23 | */ | |
1da177e4 LT |
24 | #include <linux/types.h> |
25 | #include <linux/pci.h> | |
26 | #include <linux/kernel.h> | |
1da177e4 LT |
27 | |
28 | #include <asm/mips-boards/msc01_pci.h> | |
29 | ||
70342287 | 30 | #define PCI_ACCESS_READ 0 |
1da177e4 LT |
31 | #define PCI_ACCESS_WRITE 1 |
32 | ||
33 | /* | |
34 | * PCI configuration cycle AD bus definition | |
35 | */ | |
36 | /* Type 0 */ | |
70342287 RB |
37 | #define PCI_CFG_TYPE0_REG_SHF 0 |
38 | #define PCI_CFG_TYPE0_FUNC_SHF 8 | |
1da177e4 LT |
39 | |
40 | /* Type 1 */ | |
70342287 RB |
41 | #define PCI_CFG_TYPE1_REG_SHF 0 |
42 | #define PCI_CFG_TYPE1_FUNC_SHF 8 | |
43 | #define PCI_CFG_TYPE1_DEV_SHF 11 | |
44 | #define PCI_CFG_TYPE1_BUS_SHF 16 | |
1da177e4 LT |
45 | |
46 | static int msc_pcibios_config_access(unsigned char access_type, | |
47 | struct pci_bus *bus, unsigned int devfn, int where, u32 * data) | |
48 | { | |
49 | unsigned char busnum = bus->number; | |
1da177e4 LT |
50 | u32 intr; |
51 | ||
1da177e4 LT |
52 | /* Clear status register bits. */ |
53 | MSC_WRITE(MSC01_PCI_INTSTAT, | |
54 | (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT)); | |
55 | ||
1da177e4 LT |
56 | MSC_WRITE(MSC01_PCI_CFGADDR, |
57 | ((busnum << MSC01_PCI_CFGADDR_BNUM_SHF) | | |
aa0980b8 MR |
58 | (PCI_SLOT(devfn) << MSC01_PCI_CFGADDR_DNUM_SHF) | |
59 | (PCI_FUNC(devfn) << MSC01_PCI_CFGADDR_FNUM_SHF) | | |
60 | ((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF))); | |
1da177e4 LT |
61 | |
62 | /* Perform access */ | |
63 | if (access_type == PCI_ACCESS_WRITE) | |
64 | MSC_WRITE(MSC01_PCI_CFGDATA, *data); | |
65 | else | |
66 | MSC_READ(MSC01_PCI_CFGDATA, *data); | |
67 | ||
68 | /* Detect Master/Target abort */ | |
69 | MSC_READ(MSC01_PCI_INTSTAT, intr); | |
aa0980b8 | 70 | if (intr & (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT)) { |
1da177e4 LT |
71 | /* Error occurred */ |
72 | ||
73 | /* Clear bits */ | |
1da177e4 | 74 | MSC_WRITE(MSC01_PCI_INTSTAT, |
aa0980b8 | 75 | (MSC01_PCI_INTCFG_MA_BIT | MSC01_PCI_INTCFG_TA_BIT)); |
1da177e4 LT |
76 | |
77 | return -1; | |
78 | } | |
79 | ||
80 | return 0; | |
81 | } | |
82 | ||
83 | ||
84 | /* | |
85 | * We can't address 8 and 16 bit words directly. Instead we have to | |
86 | * read/write a 32bit word and mask/modify the data we actually want. | |
87 | */ | |
88 | static int msc_pcibios_read(struct pci_bus *bus, unsigned int devfn, | |
89 | int where, int size, u32 * val) | |
90 | { | |
91 | u32 data = 0; | |
92 | ||
93 | if ((size == 2) && (where & 1)) | |
94 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
95 | else if ((size == 4) && (where & 3)) | |
96 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
97 | ||
98 | if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where, | |
70342287 | 99 | &data)) |
1da177e4 LT |
100 | return -1; |
101 | ||
102 | if (size == 1) | |
103 | *val = (data >> ((where & 3) << 3)) & 0xff; | |
104 | else if (size == 2) | |
105 | *val = (data >> ((where & 3) << 3)) & 0xffff; | |
106 | else | |
107 | *val = data; | |
108 | ||
109 | return PCIBIOS_SUCCESSFUL; | |
110 | } | |
111 | ||
112 | static int msc_pcibios_write(struct pci_bus *bus, unsigned int devfn, | |
113 | int where, int size, u32 val) | |
114 | { | |
115 | u32 data = 0; | |
116 | ||
117 | if ((size == 2) && (where & 1)) | |
118 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
119 | else if ((size == 4) && (where & 3)) | |
120 | return PCIBIOS_BAD_REGISTER_NUMBER; | |
121 | ||
122 | if (size == 4) | |
123 | data = val; | |
124 | else { | |
125 | if (msc_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | |
70342287 | 126 | where, &data)) |
1da177e4 LT |
127 | return -1; |
128 | ||
129 | if (size == 1) | |
130 | data = (data & ~(0xff << ((where & 3) << 3))) | | |
131 | (val << ((where & 3) << 3)); | |
132 | else if (size == 2) | |
133 | data = (data & ~(0xffff << ((where & 3) << 3))) | | |
134 | (val << ((where & 3) << 3)); | |
135 | } | |
136 | ||
137 | if (msc_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where, | |
138 | &data)) | |
139 | return -1; | |
140 | ||
141 | return PCIBIOS_SUCCESSFUL; | |
142 | } | |
143 | ||
144 | struct pci_ops msc_pci_ops = { | |
145 | .read = msc_pcibios_read, | |
146 | .write = msc_pcibios_write | |
147 | }; |