diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/pci/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/pci/fixup-pmcmsp.c | 216 | ||||
-rw-r--r-- | arch/mips/pci/ops-pmcmsp.c | 994 | ||||
-rw-r--r-- | arch/mips/pmc-sierra/msp71xx/msp_pci.c | 50 |
4 files changed, 1263 insertions, 0 deletions
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 276a10b06bb5..c5845db55984 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile | |||
@@ -32,6 +32,9 @@ obj-$(CONFIG_LEMOTE_FULONG) += fixup-lm2e.o ops-bonito64.o | |||
32 | obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o | 32 | obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o |
33 | obj-$(CONFIG_MOMENCO_OCELOT) += fixup-ocelot.o pci-ocelot.o | 33 | obj-$(CONFIG_MOMENCO_OCELOT) += fixup-ocelot.o pci-ocelot.o |
34 | obj-$(CONFIG_MOMENCO_OCELOT_3) += fixup-ocelot3.o | 34 | obj-$(CONFIG_MOMENCO_OCELOT_3) += fixup-ocelot3.o |
35 | obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o | ||
36 | obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o | ||
37 | obj-$(CONFIG_PMC_MSP7120_FPGA) += fixup-pmcmsp.o ops-pmcmsp.o | ||
35 | obj-$(CONFIG_PMC_YOSEMITE) += fixup-yosemite.o ops-titan.o ops-titan-ht.o \ | 38 | obj-$(CONFIG_PMC_YOSEMITE) += fixup-yosemite.o ops-titan.o ops-titan-ht.o \ |
36 | pci-yosemite.o | 39 | pci-yosemite.o |
37 | obj-$(CONFIG_SGI_IP27) += ops-bridge.o pci-ip27.o | 40 | obj-$(CONFIG_SGI_IP27) += ops-bridge.o pci-ip27.o |
diff --git a/arch/mips/pci/fixup-pmcmsp.c b/arch/mips/pci/fixup-pmcmsp.c new file mode 100644 index 000000000000..00261211dbfa --- /dev/null +++ b/arch/mips/pci/fixup-pmcmsp.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* | ||
2 | * PMC-Sierra MSP board specific pci fixups. | ||
3 | * | ||
4 | * Copyright 2001 MontaVista Software Inc. | ||
5 | * Copyright 2005-2007 PMC-Sierra, Inc | ||
6 | * | ||
7 | * Author: MontaVista Software, Inc. | ||
8 | * ppopov@mvista.com or source@mvista.com | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
18 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
21 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
22 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License along | ||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | |||
31 | #ifdef CONFIG_PCI | ||
32 | |||
33 | #include <linux/types.h> | ||
34 | #include <linux/pci.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/init.h> | ||
37 | |||
38 | #include <asm/byteorder.h> | ||
39 | |||
40 | #include <msp_pci.h> | ||
41 | #include <msp_cic_int.h> | ||
42 | |||
43 | /* PCI interrupt pins */ | ||
44 | #define IRQ4 MSP_INT_EXT4 | ||
45 | #define IRQ5 MSP_INT_EXT5 | ||
46 | #define IRQ6 MSP_INT_EXT6 | ||
47 | |||
48 | #if defined(CONFIG_PMC_MSP7120_GW) | ||
49 | /* Garibaldi Board IRQ wiring to PCI slots */ | ||
50 | static char irq_tab[][5] __initdata = { | ||
51 | /* INTA INTB INTC INTD */ | ||
52 | {0, 0, 0, 0, 0 }, /* (AD[0]): Unused */ | ||
53 | {0, 0, 0, 0, 0 }, /* (AD[1]): Unused */ | ||
54 | {0, 0, 0, 0, 0 }, /* (AD[2]): Unused */ | ||
55 | {0, 0, 0, 0, 0 }, /* (AD[3]): Unused */ | ||
56 | {0, 0, 0, 0, 0 }, /* (AD[4]): Unused */ | ||
57 | {0, 0, 0, 0, 0 }, /* (AD[5]): Unused */ | ||
58 | {0, 0, 0, 0, 0 }, /* (AD[6]): Unused */ | ||
59 | {0, 0, 0, 0, 0 }, /* (AD[7]): Unused */ | ||
60 | {0, 0, 0, 0, 0 }, /* (AD[8]): Unused */ | ||
61 | {0, 0, 0, 0, 0 }, /* (AD[9]): Unused */ | ||
62 | {0, 0, 0, 0, 0 }, /* 0 (AD[10]): Unused */ | ||
63 | {0, 0, 0, 0, 0 }, /* 1 (AD[11]): Unused */ | ||
64 | {0, 0, 0, 0, 0 }, /* 2 (AD[12]): Unused */ | ||
65 | {0, 0, 0, 0, 0 }, /* 3 (AD[13]): Unused */ | ||
66 | {0, 0, 0, 0, 0 }, /* 4 (AD[14]): Unused */ | ||
67 | {0, 0, 0, 0, 0 }, /* 5 (AD[15]): Unused */ | ||
68 | {0, 0, 0, 0, 0 }, /* 6 (AD[16]): Unused */ | ||
69 | {0, 0, 0, 0, 0 }, /* 7 (AD[17]): Unused */ | ||
70 | {0, 0, 0, 0, 0 }, /* 8 (AD[18]): Unused */ | ||
71 | {0, 0, 0, 0, 0 }, /* 9 (AD[19]): Unused */ | ||
72 | {0, 0, 0, 0, 0 }, /* 10 (AD[20]): Unused */ | ||
73 | {0, 0, 0, 0, 0 }, /* 11 (AD[21]): Unused */ | ||
74 | {0, 0, 0, 0, 0 }, /* 12 (AD[22]): Unused */ | ||
75 | {0, 0, 0, 0, 0 }, /* 13 (AD[23]): Unused */ | ||
76 | {0, 0, 0, 0, 0 }, /* 14 (AD[24]): Unused */ | ||
77 | {0, 0, 0, 0, 0 }, /* 15 (AD[25]): Unused */ | ||
78 | {0, 0, 0, 0, 0 }, /* 16 (AD[26]): Unused */ | ||
79 | {0, 0, 0, 0, 0 }, /* 17 (AD[27]): Unused */ | ||
80 | {0, IRQ4, IRQ4, 0, 0 }, /* 18 (AD[28]): slot 0 */ | ||
81 | {0, 0, 0, 0, 0 }, /* 19 (AD[29]): Unused */ | ||
82 | {0, IRQ5, IRQ5, 0, 0 }, /* 20 (AD[30]): slot 1 */ | ||
83 | {0, IRQ6, IRQ6, 0, 0 } /* 21 (AD[31]): slot 2 */ | ||
84 | }; | ||
85 | |||
86 | #elif defined(CONFIG_PMC_MSP7120_EVAL) | ||
87 | |||
88 | /* MSP7120 Eval Board IRQ wiring to PCI slots */ | ||
89 | static char irq_tab[][5] __initdata = { | ||
90 | /* INTA INTB INTC INTD */ | ||
91 | {0, 0, 0, 0, 0 }, /* (AD[0]): Unused */ | ||
92 | {0, 0, 0, 0, 0 }, /* (AD[1]): Unused */ | ||
93 | {0, 0, 0, 0, 0 }, /* (AD[2]): Unused */ | ||
94 | {0, 0, 0, 0, 0 }, /* (AD[3]): Unused */ | ||
95 | {0, 0, 0, 0, 0 }, /* (AD[4]): Unused */ | ||
96 | {0, 0, 0, 0, 0 }, /* (AD[5]): Unused */ | ||
97 | {0, 0, 0, 0, 0 }, /* (AD[6]): Unused */ | ||
98 | {0, 0, 0, 0, 0 }, /* (AD[7]): Unused */ | ||
99 | {0, 0, 0, 0, 0 }, /* (AD[8]): Unused */ | ||
100 | {0, 0, 0, 0, 0 }, /* (AD[9]): Unused */ | ||
101 | {0, 0, 0, 0, 0 }, /* 0 (AD[10]): Unused */ | ||
102 | {0, 0, 0, 0, 0 }, /* 1 (AD[11]): Unused */ | ||
103 | {0, 0, 0, 0, 0 }, /* 2 (AD[12]): Unused */ | ||
104 | {0, 0, 0, 0, 0 }, /* 3 (AD[13]): Unused */ | ||
105 | {0, 0, 0, 0, 0 }, /* 4 (AD[14]): Unused */ | ||
106 | {0, 0, 0, 0, 0 }, /* 5 (AD[15]): Unused */ | ||
107 | {0, IRQ6, IRQ6, 0, 0 }, /* 6 (AD[16]): slot 3 (mini) */ | ||
108 | {0, IRQ5, IRQ5, 0, 0 }, /* 7 (AD[17]): slot 2 (mini) */ | ||
109 | {0, IRQ4, IRQ4, IRQ4, IRQ4}, /* 8 (AD[18]): slot 0 (PCI) */ | ||
110 | {0, IRQ5, IRQ5, IRQ5, IRQ5}, /* 9 (AD[19]): slot 1 (PCI) */ | ||
111 | {0, 0, 0, 0, 0 }, /* 10 (AD[20]): Unused */ | ||
112 | {0, 0, 0, 0, 0 }, /* 11 (AD[21]): Unused */ | ||
113 | {0, 0, 0, 0, 0 }, /* 12 (AD[22]): Unused */ | ||
114 | {0, 0, 0, 0, 0 }, /* 13 (AD[23]): Unused */ | ||
115 | {0, 0, 0, 0, 0 }, /* 14 (AD[24]): Unused */ | ||
116 | {0, 0, 0, 0, 0 }, /* 15 (AD[25]): Unused */ | ||
117 | {0, 0, 0, 0, 0 }, /* 16 (AD[26]): Unused */ | ||
118 | {0, 0, 0, 0, 0 }, /* 17 (AD[27]): Unused */ | ||
119 | {0, 0, 0, 0, 0 }, /* 18 (AD[28]): Unused */ | ||
120 | {0, 0, 0, 0, 0 }, /* 19 (AD[29]): Unused */ | ||
121 | {0, 0, 0, 0, 0 }, /* 20 (AD[30]): Unused */ | ||
122 | {0, 0, 0, 0, 0 } /* 21 (AD[31]): Unused */ | ||
123 | }; | ||
124 | |||
125 | #else | ||
126 | |||
127 | /* Unknown board -- don't assign any IRQs */ | ||
128 | static char irq_tab[][5] __initdata = { | ||
129 | /* INTA INTB INTC INTD */ | ||
130 | {0, 0, 0, 0, 0 }, /* (AD[0]): Unused */ | ||
131 | {0, 0, 0, 0, 0 }, /* (AD[1]): Unused */ | ||
132 | {0, 0, 0, 0, 0 }, /* (AD[2]): Unused */ | ||
133 | {0, 0, 0, 0, 0 }, /* (AD[3]): Unused */ | ||
134 | {0, 0, 0, 0, 0 }, /* (AD[4]): Unused */ | ||
135 | {0, 0, 0, 0, 0 }, /* (AD[5]): Unused */ | ||
136 | {0, 0, 0, 0, 0 }, /* (AD[6]): Unused */ | ||
137 | {0, 0, 0, 0, 0 }, /* (AD[7]): Unused */ | ||
138 | {0, 0, 0, 0, 0 }, /* (AD[8]): Unused */ | ||
139 | {0, 0, 0, 0, 0 }, /* (AD[9]): Unused */ | ||
140 | {0, 0, 0, 0, 0 }, /* 0 (AD[10]): Unused */ | ||
141 | {0, 0, 0, 0, 0 }, /* 1 (AD[11]): Unused */ | ||
142 | {0, 0, 0, 0, 0 }, /* 2 (AD[12]): Unused */ | ||
143 | {0, 0, 0, 0, 0 }, /* 3 (AD[13]): Unused */ | ||
144 | {0, 0, 0, 0, 0 }, /* 4 (AD[14]): Unused */ | ||
145 | {0, 0, 0, 0, 0 }, /* 5 (AD[15]): Unused */ | ||
146 | {0, 0, 0, 0, 0 }, /* 6 (AD[16]): Unused */ | ||
147 | {0, 0, 0, 0, 0 }, /* 7 (AD[17]): Unused */ | ||
148 | {0, 0, 0, 0, 0 }, /* 8 (AD[18]): Unused */ | ||
149 | {0, 0, 0, 0, 0 }, /* 9 (AD[19]): Unused */ | ||
150 | {0, 0, 0, 0, 0 }, /* 10 (AD[20]): Unused */ | ||
151 | {0, 0, 0, 0, 0 }, /* 11 (AD[21]): Unused */ | ||
152 | {0, 0, 0, 0, 0 }, /* 12 (AD[22]): Unused */ | ||
153 | {0, 0, 0, 0, 0 }, /* 13 (AD[23]): Unused */ | ||
154 | {0, 0, 0, 0, 0 }, /* 14 (AD[24]): Unused */ | ||
155 | {0, 0, 0, 0, 0 }, /* 15 (AD[25]): Unused */ | ||
156 | {0, 0, 0, 0, 0 }, /* 16 (AD[26]): Unused */ | ||
157 | {0, 0, 0, 0, 0 }, /* 17 (AD[27]): Unused */ | ||
158 | {0, 0, 0, 0, 0 }, /* 18 (AD[28]): Unused */ | ||
159 | {0, 0, 0, 0, 0 }, /* 19 (AD[29]): Unused */ | ||
160 | {0, 0, 0, 0, 0 }, /* 20 (AD[30]): Unused */ | ||
161 | {0, 0, 0, 0, 0 } /* 21 (AD[31]): Unused */ | ||
162 | }; | ||
163 | #endif | ||
164 | |||
165 | /***************************************************************************** | ||
166 | * | ||
167 | * FUNCTION: pcibios_plat_dev_init | ||
168 | * _________________________________________________________________________ | ||
169 | * | ||
170 | * DESCRIPTION: Perform platform specific device initialization at | ||
171 | * pci_enable_device() time. | ||
172 | * None are needed for the MSP7120 PCI Controller. | ||
173 | * | ||
174 | * INPUTS: dev - structure describing the PCI device | ||
175 | * | ||
176 | * OUTPUTS: none | ||
177 | * | ||
178 | * RETURNS: PCIBIOS_SUCCESSFUL | ||
179 | * | ||
180 | ****************************************************************************/ | ||
181 | int pcibios_plat_dev_init(struct pci_dev *dev) | ||
182 | { | ||
183 | return PCIBIOS_SUCCESSFUL; | ||
184 | } | ||
185 | |||
186 | /***************************************************************************** | ||
187 | * | ||
188 | * FUNCTION: pcibios_map_irq | ||
189 | * _________________________________________________________________________ | ||
190 | * | ||
191 | * DESCRIPTION: Perform board supplied PCI IRQ mapping routine. | ||
192 | * | ||
193 | * INPUTS: dev - unused | ||
194 | * slot - PCI slot. Identified by which bit of the AD[] bus | ||
195 | * drives the IDSEL line. AD[10] is 0, AD[31] is | ||
196 | * slot 21. | ||
197 | * pin - numbered using the scheme of the PCI_INTERRUPT_PIN | ||
198 | * field of the config header. | ||
199 | * | ||
200 | * OUTPUTS: none | ||
201 | * | ||
202 | * RETURNS: IRQ number | ||
203 | * | ||
204 | ****************************************************************************/ | ||
205 | int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
206 | { | ||
207 | #if !defined(CONFIG_PMC_MSP7120_GW) && !defined(CONFIG_PMC_MSP7120_EVAL) | ||
208 | printk(KERN_WARNING "PCI: unknown board, no PCI IRQs assigned.\n"); | ||
209 | #endif | ||
210 | printk(KERN_WARNING "PCI: irq_tab returned %d for slot=%d pin=%d\n", | ||
211 | irq_tab[slot][pin], slot, pin); | ||
212 | |||
213 | return irq_tab[slot][pin]; | ||
214 | } | ||
215 | |||
216 | #endif /* CONFIG_PCI */ | ||
diff --git a/arch/mips/pci/ops-pmcmsp.c b/arch/mips/pci/ops-pmcmsp.c new file mode 100644 index 000000000000..09fa007c1d1b --- /dev/null +++ b/arch/mips/pci/ops-pmcmsp.c | |||
@@ -0,0 +1,994 @@ | |||
1 | /* | ||
2 | * PMC-Sierra MSP board specific pci_ops | ||
3 | * | ||
4 | * Copyright 2001 MontaVista Software Inc. | ||
5 | * Copyright 2005-2007 PMC-Sierra, Inc | ||
6 | * | ||
7 | * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net | ||
8 | * | ||
9 | * Much of the code is derived from the original DDB5074 port by | ||
10 | * Geert Uytterhoeven <geert@sonycom.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #define PCI_COUNTERS 1 | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | |||
25 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | ||
26 | #include <linux/proc_fs.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | |||
33 | #include <asm/byteorder.h> | ||
34 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | ||
35 | #include <asm/mipsmtregs.h> | ||
36 | #endif | ||
37 | |||
38 | #include <msp_prom.h> | ||
39 | #include <msp_cic_int.h> | ||
40 | #include <msp_pci.h> | ||
41 | #include <msp_regs.h> | ||
42 | #include <msp_regops.h> | ||
43 | |||
44 | #define PCI_ACCESS_READ 0 | ||
45 | #define PCI_ACCESS_WRITE 1 | ||
46 | |||
47 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | ||
48 | static char proc_init; | ||
49 | extern struct proc_dir_entry *proc_bus_pci_dir; | ||
50 | unsigned int pci_int_count[32]; | ||
51 | |||
52 | static void pci_proc_init(void); | ||
53 | |||
54 | /***************************************************************************** | ||
55 | * | ||
56 | * FUNCTION: read_msp_pci_counts | ||
57 | * _________________________________________________________________________ | ||
58 | * | ||
59 | * DESCRIPTION: Prints the count of how many times each PCI | ||
60 | * interrupt has asserted. Can be invoked by the | ||
61 | * /proc filesystem. | ||
62 | * | ||
63 | * INPUTS: page - part of STDOUT calculation | ||
64 | * off - part of STDOUT calculation | ||
65 | * count - part of STDOUT calculation | ||
66 | * data - unused | ||
67 | * | ||
68 | * OUTPUTS: start - new start location | ||
69 | * eof - end of file pointer | ||
70 | * | ||
71 | * RETURNS: len - STDOUT length | ||
72 | * | ||
73 | ****************************************************************************/ | ||
74 | static int read_msp_pci_counts(char *page, char **start, off_t off, | ||
75 | int count, int *eof, void *data) | ||
76 | { | ||
77 | int i; | ||
78 | int len = 0; | ||
79 | unsigned int intcount, total = 0; | ||
80 | |||
81 | for (i = 0; i < 32; ++i) { | ||
82 | intcount = pci_int_count[i]; | ||
83 | if (intcount != 0) { | ||
84 | len += sprintf(page + len, "[%d] = %u\n", i, intcount); | ||
85 | total += intcount; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | len += sprintf(page + len, "total = %u\n", total); | ||
90 | if (len <= off+count) | ||
91 | *eof = 1; | ||
92 | |||
93 | *start = page + off; | ||
94 | len -= off; | ||
95 | if (len > count) | ||
96 | len = count; | ||
97 | if (len < 0) | ||
98 | len = 0; | ||
99 | |||
100 | return len; | ||
101 | } | ||
102 | |||
103 | /***************************************************************************** | ||
104 | * | ||
105 | * FUNCTION: gen_pci_cfg_wr | ||
106 | * _________________________________________________________________________ | ||
107 | * | ||
108 | * DESCRIPTION: Generates a configuration write cycle for debug purposes. | ||
109 | * The IDSEL line asserted and location and data written are | ||
110 | * immaterial. Just want to be able to prove that a | ||
111 | * configuration write can be correctly generated on the | ||
112 | * PCI bus. Intent is that this function by invocable from | ||
113 | * the /proc filesystem. | ||
114 | * | ||
115 | * INPUTS: page - part of STDOUT calculation | ||
116 | * off - part of STDOUT calculation | ||
117 | * count - part of STDOUT calculation | ||
118 | * data - unused | ||
119 | * | ||
120 | * OUTPUTS: start - new start location | ||
121 | * eof - end of file pointer | ||
122 | * | ||
123 | * RETURNS: len - STDOUT length | ||
124 | * | ||
125 | ****************************************************************************/ | ||
126 | static int gen_pci_cfg_wr(char *page, char **start, off_t off, | ||
127 | int count, int *eof, void *data) | ||
128 | { | ||
129 | unsigned char where = 0; /* Write to static Device/Vendor ID */ | ||
130 | unsigned char bus_num = 0; /* Bus 0 */ | ||
131 | unsigned char dev_fn = 0xF; /* Arbitrary device number */ | ||
132 | u32 wr_data = 0xFF00AA00; /* Arbitrary data */ | ||
133 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | ||
134 | int len = 0; | ||
135 | unsigned long value; | ||
136 | int intr; | ||
137 | |||
138 | len += sprintf(page + len, "PMC MSP PCI: Beginning\n"); | ||
139 | |||
140 | if (proc_init == 0) { | ||
141 | pci_proc_init(); | ||
142 | proc_init = ~0; | ||
143 | } | ||
144 | |||
145 | len += sprintf(page + len, "PMC MSP PCI: Before Cfg Wr\n"); | ||
146 | |||
147 | /* | ||
148 | * Generate PCI Configuration Write Cycle | ||
149 | */ | ||
150 | |||
151 | /* Clear cause register bits */ | ||
152 | preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F); | ||
153 | |||
154 | /* Setup address that is to appear on PCI bus */ | ||
155 | preg->config_addr = BPCI_CFGADDR_ENABLE | | ||
156 | (bus_num << BPCI_CFGADDR_BUSNUM_SHF) | | ||
157 | (dev_fn << BPCI_CFGADDR_FUNCTNUM_SHF) | | ||
158 | (where & 0xFC); | ||
159 | |||
160 | value = cpu_to_le32(wr_data); | ||
161 | |||
162 | /* Launch the PCI configuration write cycle */ | ||
163 | *PCI_CONFIG_SPACE_REG = value; | ||
164 | |||
165 | /* | ||
166 | * Check if the PCI configuration cycle (rd or wr) succeeded, by | ||
167 | * checking the status bits for errors like master or target abort. | ||
168 | */ | ||
169 | intr = preg->if_status; | ||
170 | |||
171 | len += sprintf(page + len, "PMC MSP PCI: After Cfg Wr\n"); | ||
172 | |||
173 | /* Handle STDOUT calculations */ | ||
174 | if (len <= off+count) | ||
175 | *eof = 1; | ||
176 | *start = page + off; | ||
177 | len -= off; | ||
178 | if (len > count) | ||
179 | len = count; | ||
180 | if (len < 0) | ||
181 | len = 0; | ||
182 | |||
183 | return len; | ||
184 | } | ||
185 | |||
186 | /***************************************************************************** | ||
187 | * | ||
188 | * FUNCTION: pci_proc_init | ||
189 | * _________________________________________________________________________ | ||
190 | * | ||
191 | * DESCRIPTION: Create entries in the /proc filesystem for debug access. | ||
192 | * | ||
193 | * INPUTS: none | ||
194 | * | ||
195 | * OUTPUTS: none | ||
196 | * | ||
197 | * RETURNS: none | ||
198 | * | ||
199 | ****************************************************************************/ | ||
200 | static void pci_proc_init(void) | ||
201 | { | ||
202 | create_proc_read_entry("pmc_msp_pci_rd_cnt", 0, NULL, | ||
203 | read_msp_pci_counts, NULL); | ||
204 | create_proc_read_entry("pmc_msp_pci_cfg_wr", 0, NULL, | ||
205 | gen_pci_cfg_wr, NULL); | ||
206 | } | ||
207 | #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ | ||
208 | |||
209 | spinlock_t bpci_lock = SPIN_LOCK_UNLOCKED; | ||
210 | |||
211 | /***************************************************************************** | ||
212 | * | ||
213 | * STRUCT: pci_io_resource | ||
214 | * _________________________________________________________________________ | ||
215 | * | ||
216 | * DESCRIPTION: Defines the address range that pciauto() will use to | ||
217 | * assign to the I/O BARs of PCI devices. | ||
218 | * | ||
219 | * Use the start and end addresses of the MSP7120 PCI Host | ||
220 | * Controller I/O space, in the form that they appear on the | ||
221 | * PCI bus AFTER MSP7120 has performed address translation. | ||
222 | * | ||
223 | * For I/O accesses, MSP7120 ignores OATRAN and maps I/O | ||
224 | * accesses into the bottom 0xFFF region of address space, | ||
225 | * so that is the range to put into the pci_io_resource | ||
226 | * struct. | ||
227 | * | ||
228 | * In MSP4200, the start address was 0x04 instead of the | ||
229 | * expected 0x00. Will just assume there was a good reason | ||
230 | * for this! | ||
231 | * | ||
232 | * NOTES: Linux, by default, will assign I/O space to the lowest | ||
233 | * region of address space. Since MSP7120 and Linux, | ||
234 | * by default, have no offset in between how they map, the | ||
235 | * io_offset element of pci_controller struct should be set | ||
236 | * to zero. | ||
237 | * ELEMENTS: | ||
238 | * name - String used for a meaningful name. | ||
239 | * | ||
240 | * start - Start address of MSP7120's I/O space, as MSP7120 presents | ||
241 | * the address on the PCI bus. | ||
242 | * | ||
243 | * end - End address of MSP7120's I/O space, as MSP7120 presents | ||
244 | * the address on the PCI bus. | ||
245 | * | ||
246 | * flags - Attributes indicating the type of resource. In this case, | ||
247 | * indicate I/O space. | ||
248 | * | ||
249 | ****************************************************************************/ | ||
250 | static struct resource pci_io_resource = { | ||
251 | .name = "pci IO space", | ||
252 | .start = 0x04, | ||
253 | .end = 0x0FFF, | ||
254 | .flags = IORESOURCE_IO /* I/O space */ | ||
255 | }; | ||
256 | |||
257 | /***************************************************************************** | ||
258 | * | ||
259 | * STRUCT: pci_mem_resource | ||
260 | * _________________________________________________________________________ | ||
261 | * | ||
262 | * DESCRIPTION: Defines the address range that pciauto() will use to | ||
263 | * assign to the memory BARs of PCI devices. | ||
264 | * | ||
265 | * The .start and .end values are dependent upon how address | ||
266 | * translation is performed by the OATRAN regiser. | ||
267 | * | ||
268 | * The values to use for .start and .end are the values | ||
269 | * in the form they appear on the PCI bus AFTER MSP7120 has | ||
270 | * performed OATRAN address translation. | ||
271 | * | ||
272 | * ELEMENTS: | ||
273 | * name - String used for a meaningful name. | ||
274 | * | ||
275 | * start - Start address of MSP7120's memory space, as MSP7120 presents | ||
276 | * the address on the PCI bus. | ||
277 | * | ||
278 | * end - End address of MSP7120's memory space, as MSP7120 presents | ||
279 | * the address on the PCI bus. | ||
280 | * | ||
281 | * flags - Attributes indicating the type of resource. In this case, | ||
282 | * indicate memory space. | ||
283 | * | ||
284 | ****************************************************************************/ | ||
285 | static struct resource pci_mem_resource = { | ||
286 | .name = "pci memory space", | ||
287 | .start = MSP_PCI_SPACE_BASE, | ||
288 | .end = MSP_PCI_SPACE_END, | ||
289 | .flags = IORESOURCE_MEM /* memory space */ | ||
290 | }; | ||
291 | |||
292 | /***************************************************************************** | ||
293 | * | ||
294 | * FUNCTION: bpci_interrupt | ||
295 | * _________________________________________________________________________ | ||
296 | * | ||
297 | * DESCRIPTION: PCI status interrupt handler. Updates the count of how | ||
298 | * many times each status bit has been set, then clears | ||
299 | * the status bits. If the appropriate macros are defined, | ||
300 | * these counts can be viewed via the /proc filesystem. | ||
301 | * | ||
302 | * INPUTS: irq - unused | ||
303 | * dev_id - unused | ||
304 | * pt_regs - unused | ||
305 | * | ||
306 | * OUTPUTS: none | ||
307 | * | ||
308 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
309 | * | ||
310 | ****************************************************************************/ | ||
311 | static int bpci_interrupt(int irq, void *dev_id) | ||
312 | { | ||
313 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | ||
314 | unsigned int stat = preg->if_status; | ||
315 | |||
316 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | ||
317 | int i; | ||
318 | for (i = 0; i < 32; ++i) { | ||
319 | if ((1 << i) & stat) | ||
320 | ++pci_int_count[i]; | ||
321 | } | ||
322 | #endif /* PROC_FS && PCI_COUNTERS */ | ||
323 | |||
324 | /* printk("PCI ISR: Status=%08X\n", stat); */ | ||
325 | |||
326 | /* write to clear all asserted interrupts */ | ||
327 | preg->if_status = stat; | ||
328 | |||
329 | return PCIBIOS_SUCCESSFUL; | ||
330 | } | ||
331 | |||
332 | /***************************************************************************** | ||
333 | * | ||
334 | * FUNCTION: msp_pcibios_config_access | ||
335 | * _________________________________________________________________________ | ||
336 | * | ||
337 | * DESCRIPTION: Performs a PCI configuration access (rd or wr), then | ||
338 | * checks that the access succeeded by querying MSP7120's | ||
339 | * PCI status bits. | ||
340 | * | ||
341 | * INPUTS: | ||
342 | * access_type - kind of PCI configuration cycle to perform | ||
343 | * (read or write). Legal values are | ||
344 | * PCI_ACCESS_WRITE and PCI_ACCESS_READ. | ||
345 | * | ||
346 | * bus - pointer to the bus number of the device to | ||
347 | * be targetted for the configuration cycle. | ||
348 | * The only element of the pci_bus structure | ||
349 | * used is bus->number. This argument determines | ||
350 | * if the configuration access will be Type 0 or | ||
351 | * Type 1. Since MSP7120 assumes itself to be the | ||
352 | * PCI Host, any non-zero bus->number generates | ||
353 | * a Type 1 access. | ||
354 | * | ||
355 | * devfn - this is an 8-bit field. The lower three bits | ||
356 | * specify the function number of the device to | ||
357 | * be targetted for the configuration cycle, with | ||
358 | * all three-bit combinations being legal. The | ||
359 | * upper five bits specify the device number, | ||
360 | * with legal values being 10 to 31. | ||
361 | * | ||
362 | * where - address within the Configuration Header | ||
363 | * space to access. | ||
364 | * | ||
365 | * data - for write accesses, contains the data to | ||
366 | * write. | ||
367 | * | ||
368 | * OUTPUTS: | ||
369 | * data - for read accesses, contains the value read. | ||
370 | * | ||
371 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
372 | * -1 - access failure | ||
373 | * | ||
374 | ****************************************************************************/ | ||
375 | int msp_pcibios_config_access(unsigned char access_type, | ||
376 | struct pci_bus *bus, | ||
377 | unsigned int devfn, | ||
378 | unsigned char where, | ||
379 | u32 *data) | ||
380 | { | ||
381 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | ||
382 | unsigned char bus_num = bus->number; | ||
383 | unsigned char dev_fn = (unsigned char)devfn; | ||
384 | unsigned long flags; | ||
385 | unsigned long intr; | ||
386 | unsigned long value; | ||
387 | static char pciirqflag; | ||
388 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | ||
389 | unsigned int vpe_status; | ||
390 | #endif | ||
391 | |||
392 | #if defined(CONFIG_PROC_FS) && defined(PCI_COUNTERS) | ||
393 | if (proc_init == 0) { | ||
394 | pci_proc_init(); | ||
395 | proc_init = ~0; | ||
396 | } | ||
397 | #endif /* CONFIG_PROC_FS && PCI_COUNTERS */ | ||
398 | |||
399 | /* | ||
400 | * Just the first time this function invokes, allocate | ||
401 | * an interrupt line for PCI host status interrupts. The | ||
402 | * allocation assigns an interrupt handler to the interrupt. | ||
403 | */ | ||
404 | if (pciirqflag == 0) { | ||
405 | request_irq(MSP_INT_PCI,/* Hardcoded internal MSP7120 wiring */ | ||
406 | bpci_interrupt, | ||
407 | SA_SHIRQ | SA_INTERRUPT, | ||
408 | "PMC MSP PCI Host", | ||
409 | preg); | ||
410 | pciirqflag = ~0; | ||
411 | } | ||
412 | |||
413 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | ||
414 | local_irq_save(flags); | ||
415 | vpe_status = dvpe(); | ||
416 | #else | ||
417 | spin_lock_irqsave(&bpci_lock, flags); | ||
418 | #endif | ||
419 | |||
420 | /* | ||
421 | * Clear PCI cause register bits. | ||
422 | * | ||
423 | * In Polo, the PCI Host had a dedicated DMA called the | ||
424 | * Block Copy (not to be confused with the general purpose Block | ||
425 | * Copy Engine block). There appear to have been special interrupts | ||
426 | * for this Block Copy, called Block Copy 0 Fault (BC0F) and | ||
427 | * Block Copy 1 Fault (BC1F). MSP4200 and MSP7120 don't have this | ||
428 | * dedicated Block Copy block, so these two interrupts are now | ||
429 | * marked reserved. In case the Block Copy is resurrected in a | ||
430 | * future design, maintain the code that treats these two interrupts | ||
431 | * specially. | ||
432 | * | ||
433 | * Write to clear all interrupts in the PCI status register, aside | ||
434 | * from BC0F and BC1F. | ||
435 | */ | ||
436 | preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F); | ||
437 | |||
438 | /* Setup address that is to appear on PCI bus */ | ||
439 | preg->config_addr = BPCI_CFGADDR_ENABLE | | ||
440 | (bus_num << BPCI_CFGADDR_BUSNUM_SHF) | | ||
441 | (dev_fn << BPCI_CFGADDR_FUNCTNUM_SHF) | | ||
442 | (where & 0xFC); | ||
443 | |||
444 | /* IF access is a PCI configuration write */ | ||
445 | if (access_type == PCI_ACCESS_WRITE) { | ||
446 | value = cpu_to_le32(*data); | ||
447 | *PCI_CONFIG_SPACE_REG = value; | ||
448 | } else { | ||
449 | /* ELSE access is a PCI configuration read */ | ||
450 | value = le32_to_cpu(*PCI_CONFIG_SPACE_REG); | ||
451 | *data = value; | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * Check if the PCI configuration cycle (rd or wr) succeeded, by | ||
456 | * checking the status bits for errors like master or target abort. | ||
457 | */ | ||
458 | intr = preg->if_status; | ||
459 | |||
460 | /* Clear config access */ | ||
461 | preg->config_addr = 0; | ||
462 | |||
463 | /* IF error occurred */ | ||
464 | if (intr & ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F)) { | ||
465 | /* Clear status bits */ | ||
466 | preg->if_status = ~(BPCI_IFSTATUS_BC0F | BPCI_IFSTATUS_BC1F); | ||
467 | |||
468 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | ||
469 | evpe(vpe_status); | ||
470 | local_irq_restore(flags); | ||
471 | #else | ||
472 | spin_unlock_irqrestore(&bpci_lock, flags); | ||
473 | #endif | ||
474 | |||
475 | return -1; | ||
476 | } | ||
477 | |||
478 | #if defined(CONFIG_PMC_MSP7120_GW) || defined(CONFIG_PMC_MSP7120_EVAL) | ||
479 | evpe(vpe_status); | ||
480 | local_irq_restore(flags); | ||
481 | #else | ||
482 | spin_unlock_irqrestore(&bpci_lock, flags); | ||
483 | #endif | ||
484 | |||
485 | return PCIBIOS_SUCCESSFUL; | ||
486 | } | ||
487 | |||
488 | /***************************************************************************** | ||
489 | * | ||
490 | * FUNCTION: msp_pcibios_read_config_byte | ||
491 | * _________________________________________________________________________ | ||
492 | * | ||
493 | * DESCRIPTION: Read a byte from PCI configuration address spac | ||
494 | * Since the hardware can't address 8 bit chunks | ||
495 | * directly, read a 32-bit chunk, then mask off extraneous | ||
496 | * bits. | ||
497 | * | ||
498 | * INPUTS bus - structure containing attributes for the PCI bus | ||
499 | * that the read is destined for. | ||
500 | * devfn - device/function combination that the read is | ||
501 | * destined for. | ||
502 | * where - register within the Configuration Header space | ||
503 | * to access. | ||
504 | * | ||
505 | * OUTPUTS val - read data | ||
506 | * | ||
507 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
508 | * -1 - read access failure | ||
509 | * | ||
510 | ****************************************************************************/ | ||
511 | static int | ||
512 | msp_pcibios_read_config_byte(struct pci_bus *bus, | ||
513 | unsigned int devfn, | ||
514 | int where, | ||
515 | u32 *val) | ||
516 | { | ||
517 | u32 data = 0; | ||
518 | |||
519 | /* | ||
520 | * If the config access did not complete normally (e.g., underwent | ||
521 | * master abort) do the PCI compliant thing, which is to supply an | ||
522 | * all ones value. | ||
523 | */ | ||
524 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | ||
525 | where, &data)) { | ||
526 | *val = 0xFFFFFFFF; | ||
527 | return -1; | ||
528 | } | ||
529 | |||
530 | *val = (data >> ((where & 3) << 3)) & 0x0ff; | ||
531 | |||
532 | return PCIBIOS_SUCCESSFUL; | ||
533 | } | ||
534 | |||
535 | /***************************************************************************** | ||
536 | * | ||
537 | * FUNCTION: msp_pcibios_read_config_word | ||
538 | * _________________________________________________________________________ | ||
539 | * | ||
540 | * DESCRIPTION: Read a word (16 bits) from PCI configuration address space. | ||
541 | * Since the hardware can't address 16 bit chunks | ||
542 | * directly, read a 32-bit chunk, then mask off extraneous | ||
543 | * bits. | ||
544 | * | ||
545 | * INPUTS bus - structure containing attributes for the PCI bus | ||
546 | * that the read is destined for. | ||
547 | * devfn - device/function combination that the read is | ||
548 | * destined for. | ||
549 | * where - register within the Configuration Header space | ||
550 | * to access. | ||
551 | * | ||
552 | * OUTPUTS val - read data | ||
553 | * | ||
554 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
555 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | ||
556 | * -1 - read access failure | ||
557 | * | ||
558 | ****************************************************************************/ | ||
559 | static int | ||
560 | msp_pcibios_read_config_word(struct pci_bus *bus, | ||
561 | unsigned int devfn, | ||
562 | int where, | ||
563 | u32 *val) | ||
564 | { | ||
565 | u32 data = 0; | ||
566 | |||
567 | /* if (where & 1) */ /* Commented out non-compliant code. | ||
568 | * Should allow word access to configuration | ||
569 | * registers, with only exception being when | ||
570 | * the word access would wrap around into | ||
571 | * the next dword. | ||
572 | */ | ||
573 | if ((where & 3) == 3) { | ||
574 | *val = 0xFFFFFFFF; | ||
575 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * If the config access did not complete normally (e.g., underwent | ||
580 | * master abort) do the PCI compliant thing, which is to supply an | ||
581 | * all ones value. | ||
582 | */ | ||
583 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | ||
584 | where, &data)) { | ||
585 | *val = 0xFFFFFFFF; | ||
586 | return -1; | ||
587 | } | ||
588 | |||
589 | *val = (data >> ((where & 3) << 3)) & 0x0ffff; | ||
590 | |||
591 | return PCIBIOS_SUCCESSFUL; | ||
592 | } | ||
593 | |||
594 | /***************************************************************************** | ||
595 | * | ||
596 | * FUNCTION: msp_pcibios_read_config_dword | ||
597 | * _________________________________________________________________________ | ||
598 | * | ||
599 | * DESCRIPTION: Read a double word (32 bits) from PCI configuration | ||
600 | * address space. | ||
601 | * | ||
602 | * INPUTS bus - structure containing attributes for the PCI bus | ||
603 | * that the read is destined for. | ||
604 | * devfn - device/function combination that the read is | ||
605 | * destined for. | ||
606 | * where - register within the Configuration Header space | ||
607 | * to access. | ||
608 | * | ||
609 | * OUTPUTS val - read data | ||
610 | * | ||
611 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
612 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | ||
613 | * -1 - read access failure | ||
614 | * | ||
615 | ****************************************************************************/ | ||
616 | static int | ||
617 | msp_pcibios_read_config_dword(struct pci_bus *bus, | ||
618 | unsigned int devfn, | ||
619 | int where, | ||
620 | u32 *val) | ||
621 | { | ||
622 | u32 data = 0; | ||
623 | |||
624 | /* Address must be dword aligned. */ | ||
625 | if (where & 3) { | ||
626 | *val = 0xFFFFFFFF; | ||
627 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
628 | } | ||
629 | |||
630 | /* | ||
631 | * If the config access did not complete normally (e.g., underwent | ||
632 | * master abort) do the PCI compliant thing, which is to supply an | ||
633 | * all ones value. | ||
634 | */ | ||
635 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | ||
636 | where, &data)) { | ||
637 | *val = 0xFFFFFFFF; | ||
638 | return -1; | ||
639 | } | ||
640 | |||
641 | *val = data; | ||
642 | |||
643 | return PCIBIOS_SUCCESSFUL; | ||
644 | } | ||
645 | |||
646 | /***************************************************************************** | ||
647 | * | ||
648 | * FUNCTION: msp_pcibios_write_config_byte | ||
649 | * _________________________________________________________________________ | ||
650 | * | ||
651 | * DESCRIPTION: Write a byte to PCI configuration address space. | ||
652 | * Since the hardware can't address 8 bit chunks | ||
653 | * directly, a read-modify-write is performed. | ||
654 | * | ||
655 | * INPUTS bus - structure containing attributes for the PCI bus | ||
656 | * that the write is destined for. | ||
657 | * devfn - device/function combination that the write is | ||
658 | * destined for. | ||
659 | * where - register within the Configuration Header space | ||
660 | * to access. | ||
661 | * val - value to write | ||
662 | * | ||
663 | * OUTPUTS none | ||
664 | * | ||
665 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
666 | * -1 - write access failure | ||
667 | * | ||
668 | ****************************************************************************/ | ||
669 | static int | ||
670 | msp_pcibios_write_config_byte(struct pci_bus *bus, | ||
671 | unsigned int devfn, | ||
672 | int where, | ||
673 | u8 val) | ||
674 | { | ||
675 | u32 data = 0; | ||
676 | |||
677 | /* read config space */ | ||
678 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | ||
679 | where, &data)) | ||
680 | return -1; | ||
681 | |||
682 | /* modify the byte within the dword */ | ||
683 | data = (data & ~(0xff << ((where & 3) << 3))) | | ||
684 | (val << ((where & 3) << 3)); | ||
685 | |||
686 | /* write back the full dword */ | ||
687 | if (msp_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, | ||
688 | where, &data)) | ||
689 | return -1; | ||
690 | |||
691 | return PCIBIOS_SUCCESSFUL; | ||
692 | } | ||
693 | |||
694 | /***************************************************************************** | ||
695 | * | ||
696 | * FUNCTION: msp_pcibios_write_config_word | ||
697 | * _________________________________________________________________________ | ||
698 | * | ||
699 | * DESCRIPTION: Write a word (16-bits) to PCI configuration address space. | ||
700 | * Since the hardware can't address 16 bit chunks | ||
701 | * directly, a read-modify-write is performed. | ||
702 | * | ||
703 | * INPUTS bus - structure containing attributes for the PCI bus | ||
704 | * that the write is destined for. | ||
705 | * devfn - device/function combination that the write is | ||
706 | * destined for. | ||
707 | * where - register within the Configuration Header space | ||
708 | * to access. | ||
709 | * val - value to write | ||
710 | * | ||
711 | * OUTPUTS none | ||
712 | * | ||
713 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
714 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | ||
715 | * -1 - write access failure | ||
716 | * | ||
717 | ****************************************************************************/ | ||
718 | static int | ||
719 | msp_pcibios_write_config_word(struct pci_bus *bus, | ||
720 | unsigned int devfn, | ||
721 | int where, | ||
722 | u16 val) | ||
723 | { | ||
724 | u32 data = 0; | ||
725 | |||
726 | /* Fixed non-compliance: if (where & 1) */ | ||
727 | if ((where & 3) == 3) | ||
728 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
729 | |||
730 | /* read config space */ | ||
731 | if (msp_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, | ||
732 | where, &data)) | ||
733 | return -1; | ||
734 | |||
735 | /* modify the word within the dword */ | ||
736 | data = (data & ~(0xffff << ((where & 3) << 3))) | | ||
737 | (val << ((where & 3) << 3)); | ||
738 | |||
739 | /* write back the full dword */ | ||
740 | if (msp_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, | ||
741 | where, &data)) | ||
742 | return -1; | ||
743 | |||
744 | return PCIBIOS_SUCCESSFUL; | ||
745 | } | ||
746 | |||
747 | /***************************************************************************** | ||
748 | * | ||
749 | * FUNCTION: msp_pcibios_write_config_dword | ||
750 | * _________________________________________________________________________ | ||
751 | * | ||
752 | * DESCRIPTION: Write a double word (32-bits) to PCI configuration address | ||
753 | * space. | ||
754 | * | ||
755 | * INPUTS bus - structure containing attributes for the PCI bus | ||
756 | * that the write is destined for. | ||
757 | * devfn - device/function combination that the write is | ||
758 | * destined for. | ||
759 | * where - register within the Configuration Header space | ||
760 | * to access. | ||
761 | * val - value to write | ||
762 | * | ||
763 | * OUTPUTS none | ||
764 | * | ||
765 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
766 | * PCIBIOS_BAD_REGISTER_NUMBER - bad register address | ||
767 | * -1 - write access failure | ||
768 | * | ||
769 | ****************************************************************************/ | ||
770 | static int | ||
771 | msp_pcibios_write_config_dword(struct pci_bus *bus, | ||
772 | unsigned int devfn, | ||
773 | int where, | ||
774 | u32 val) | ||
775 | { | ||
776 | /* check that address is dword aligned */ | ||
777 | if (where & 3) | ||
778 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
779 | |||
780 | /* perform write */ | ||
781 | if (msp_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, | ||
782 | where, &val)) | ||
783 | return -1; | ||
784 | |||
785 | return PCIBIOS_SUCCESSFUL; | ||
786 | } | ||
787 | |||
788 | /***************************************************************************** | ||
789 | * | ||
790 | * FUNCTION: msp_pcibios_read_config | ||
791 | * _________________________________________________________________________ | ||
792 | * | ||
793 | * DESCRIPTION: Interface the PCI configuration read request with | ||
794 | * the appropriate function, based on how many bytes | ||
795 | * the read request is. | ||
796 | * | ||
797 | * INPUTS bus - structure containing attributes for the PCI bus | ||
798 | * that the write is destined for. | ||
799 | * devfn - device/function combination that the write is | ||
800 | * destined for. | ||
801 | * where - register within the Configuration Header space | ||
802 | * to access. | ||
803 | * size - in units of bytes, should be 1, 2, or 4. | ||
804 | * | ||
805 | * OUTPUTS val - value read, with any extraneous bytes masked | ||
806 | * to zero. | ||
807 | * | ||
808 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
809 | * -1 - failure | ||
810 | * | ||
811 | ****************************************************************************/ | ||
812 | int | ||
813 | msp_pcibios_read_config(struct pci_bus *bus, | ||
814 | unsigned int devfn, | ||
815 | int where, | ||
816 | int size, | ||
817 | u32 *val) | ||
818 | { | ||
819 | if (size == 1) { | ||
820 | if (msp_pcibios_read_config_byte(bus, devfn, where, val)) { | ||
821 | return -1; | ||
822 | } | ||
823 | } else if (size == 2) { | ||
824 | if (msp_pcibios_read_config_word(bus, devfn, where, val)) { | ||
825 | return -1; | ||
826 | } | ||
827 | } else if (size == 4) { | ||
828 | if (msp_pcibios_read_config_dword(bus, devfn, where, val)) { | ||
829 | return -1; | ||
830 | } | ||
831 | } else { | ||
832 | *val = 0xFFFFFFFF; | ||
833 | return -1; | ||
834 | } | ||
835 | |||
836 | return PCIBIOS_SUCCESSFUL; | ||
837 | } | ||
838 | |||
839 | /***************************************************************************** | ||
840 | * | ||
841 | * FUNCTION: msp_pcibios_write_config | ||
842 | * _________________________________________________________________________ | ||
843 | * | ||
844 | * DESCRIPTION: Interface the PCI configuration write request with | ||
845 | * the appropriate function, based on how many bytes | ||
846 | * the read request is. | ||
847 | * | ||
848 | * INPUTS bus - structure containing attributes for the PCI bus | ||
849 | * that the write is destined for. | ||
850 | * devfn - device/function combination that the write is | ||
851 | * destined for. | ||
852 | * where - register within the Configuration Header space | ||
853 | * to access. | ||
854 | * size - in units of bytes, should be 1, 2, or 4. | ||
855 | * val - value to write | ||
856 | * | ||
857 | * OUTPUTS: none | ||
858 | * | ||
859 | * RETURNS: PCIBIOS_SUCCESSFUL - success | ||
860 | * -1 - failure | ||
861 | * | ||
862 | ****************************************************************************/ | ||
863 | int | ||
864 | msp_pcibios_write_config(struct pci_bus *bus, | ||
865 | unsigned int devfn, | ||
866 | int where, | ||
867 | int size, | ||
868 | u32 val) | ||
869 | { | ||
870 | if (size == 1) { | ||
871 | if (msp_pcibios_write_config_byte(bus, devfn, | ||
872 | where, (u8)(0xFF & val))) { | ||
873 | return -1; | ||
874 | } | ||
875 | } else if (size == 2) { | ||
876 | if (msp_pcibios_write_config_word(bus, devfn, | ||
877 | where, (u16)(0xFFFF & val))) { | ||
878 | return -1; | ||
879 | } | ||
880 | } else if (size == 4) { | ||
881 | if (msp_pcibios_write_config_dword(bus, devfn, where, val)) { | ||
882 | return -1; | ||
883 | } | ||
884 | } else { | ||
885 | return -1; | ||
886 | } | ||
887 | |||
888 | return PCIBIOS_SUCCESSFUL; | ||
889 | } | ||
890 | |||
891 | /***************************************************************************** | ||
892 | * | ||
893 | * STRUCTURE: msp_pci_ops | ||
894 | * _________________________________________________________________________ | ||
895 | * | ||
896 | * DESCRIPTION: structure to abstract the hardware specific PCI | ||
897 | * configuration accesses. | ||
898 | * | ||
899 | * ELEMENTS: | ||
900 | * read - function for Linux to generate PCI Configuration reads. | ||
901 | * write - function for Linux to generate PCI Configuration writes. | ||
902 | * | ||
903 | ****************************************************************************/ | ||
904 | struct pci_ops msp_pci_ops = { | ||
905 | .read = msp_pcibios_read_config, | ||
906 | .write = msp_pcibios_write_config | ||
907 | }; | ||
908 | |||
909 | /***************************************************************************** | ||
910 | * | ||
911 | * STRUCTURE: msp_pci_controller | ||
912 | * _________________________________________________________________________ | ||
913 | * | ||
914 | * Describes the attributes of the MSP7120 PCI Host Controller | ||
915 | * | ||
916 | * ELEMENTS: | ||
917 | * pci_ops - abstracts the hardware specific PCI configuration | ||
918 | * accesses. | ||
919 | * | ||
920 | * mem_resource - address range pciauto() uses to assign to PCI device | ||
921 | * memory BARs. | ||
922 | * | ||
923 | * mem_offset - offset between how MSP7120 outbound PCI memory | ||
924 | * transaction addresses appear on the PCI bus and how Linux | ||
925 | * wants to configure memory BARs of the PCI devices. | ||
926 | * MSP7120 does nothing funky, so just set to zero. | ||
927 | * | ||
928 | * io_resource - address range pciauto() uses to assign to PCI device | ||
929 | * I/O BARs. | ||
930 | * | ||
931 | * io_offset - offset between how MSP7120 outbound PCI I/O | ||
932 | * transaction addresses appear on the PCI bus and how | ||
933 | * Linux defaults to configure I/O BARs of the PCI devices. | ||
934 | * MSP7120 maps outbound I/O accesses into the bottom | ||
935 | * bottom 4K of PCI address space (and ignores OATRAN). | ||
936 | * Since the Linux default is to configure I/O BARs to the | ||
937 | * bottom 4K, no special offset is needed. Just set to zero. | ||
938 | * | ||
939 | ****************************************************************************/ | ||
940 | static struct pci_controller msp_pci_controller = { | ||
941 | .pci_ops = &msp_pci_ops, | ||
942 | .mem_resource = &pci_mem_resource, | ||
943 | .mem_offset = 0, | ||
944 | .io_resource = &pci_io_resource, | ||
945 | .io_offset = 0 | ||
946 | }; | ||
947 | |||
948 | /***************************************************************************** | ||
949 | * | ||
950 | * FUNCTION: msp_pci_init | ||
951 | * _________________________________________________________________________ | ||
952 | * | ||
953 | * DESCRIPTION: Initialize the PCI Host Controller and register it with | ||
954 | * Linux so Linux can seize control of the PCI bus. | ||
955 | * | ||
956 | ****************************************************************************/ | ||
957 | void __init msp_pci_init(void) | ||
958 | { | ||
959 | struct msp_pci_regs *preg = (void *)PCI_BASE_REG; | ||
960 | u32 id; | ||
961 | |||
962 | /* Extract Device ID */ | ||
963 | id = read_reg32(PCI_JTAG_DEVID_REG, 0xFFFF) >> 12; | ||
964 | |||
965 | /* Check if JTAG ID identifies MSP7120 */ | ||
966 | if (!MSP_HAS_PCI(id)) { | ||
967 | printk(KERN_WARNING "PCI: No PCI; id reads as %x\n", id); | ||
968 | goto no_pci; | ||
969 | } | ||
970 | |||
971 | /* | ||
972 | * Enable flushing of the PCI-SDRAM queue upon a read | ||
973 | * of the SDRAM's Memory Configuration Register. | ||
974 | */ | ||
975 | *(unsigned long *)QFLUSH_REG_1 = 3; | ||
976 | |||
977 | /* Configure PCI Host Controller. */ | ||
978 | preg->if_status = ~0; /* Clear cause register bits */ | ||
979 | preg->config_addr = 0; /* Clear config access */ | ||
980 | preg->oatran = MSP_PCI_OATRAN; /* PCI outbound addr translation */ | ||
981 | preg->if_mask = 0xF8BF87C0; /* Enable all PCI status interrupts */ | ||
982 | |||
983 | /* configure so inb(), outb(), and family are functional */ | ||
984 | set_io_port_base(MSP_PCI_IOSPACE_BASE); | ||
985 | |||
986 | /* Tell Linux the details of the MSP7120 PCI Host Controller */ | ||
987 | register_pci_controller(&msp_pci_controller); | ||
988 | |||
989 | return; | ||
990 | |||
991 | no_pci: | ||
992 | /* Disable PCI channel */ | ||
993 | printk(KERN_WARNING "PCI: no host PCI bus detected\n"); | ||
994 | } | ||
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_pci.c b/arch/mips/pmc-sierra/msp71xx/msp_pci.c new file mode 100644 index 000000000000..f764fe7748d6 --- /dev/null +++ b/arch/mips/pmc-sierra/msp71xx/msp_pci.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * The setup file for PCI related hardware on PMC-Sierra MSP processors. | ||
3 | * | ||
4 | * Copyright 2005-2006 PMC-Sierra, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
12 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
14 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
15 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
16 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
17 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
18 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
19 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
20 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License along | ||
23 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
24 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | |||
29 | #include <msp_prom.h> | ||
30 | #include <msp_regs.h> | ||
31 | |||
32 | extern void msp_pci_init(void); | ||
33 | |||
34 | static int __init msp_pci_setup(void) | ||
35 | { | ||
36 | #if 0 /* Linux 2.6 initialization code to be completed */ | ||
37 | if (getdeviceid() & DEV_ID_SINGLE_PC) { | ||
38 | /* If single card mode */ | ||
39 | slmRegs *sreg = (slmRegs *) SREG_BASE; | ||
40 | |||
41 | sreg->single_pc_enable = SINGLE_PCCARD; | ||
42 | } | ||
43 | #endif | ||
44 | |||
45 | msp_pci_init(); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | subsys_initcall(msp_pci_setup); | ||