diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sh/drivers |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/sh/drivers')
27 files changed, 4072 insertions, 0 deletions
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile new file mode 100644 index 000000000000..bd6726cde398 --- /dev/null +++ b/arch/sh/drivers/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the Linux SuperH-specific device drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PCI) += pci/ | ||
6 | obj-$(CONFIG_SH_DMA) += dma/ | ||
7 | |||
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig new file mode 100644 index 000000000000..0f15216cd39d --- /dev/null +++ b/arch/sh/drivers/dma/Kconfig | |||
@@ -0,0 +1,55 @@ | |||
1 | menu "DMA support" | ||
2 | |||
3 | config SH_DMA | ||
4 | bool "DMA controller (DMAC) support" | ||
5 | help | ||
6 | Selecting this option will provide same API as PC's Direct Memory | ||
7 | Access Controller(8237A) for SuperH DMAC. | ||
8 | |||
9 | If unsure, say N. | ||
10 | |||
11 | config NR_ONCHIP_DMA_CHANNELS | ||
12 | depends on SH_DMA | ||
13 | int "Number of on-chip DMAC channels" | ||
14 | default "4" | ||
15 | help | ||
16 | This allows you to specify the number of channels that the on-chip | ||
17 | DMAC supports. This will be 4 for SH7750/SH7751 and 8 for the | ||
18 | SH7750R/SH7751R. | ||
19 | |||
20 | config NR_DMA_CHANNELS_BOOL | ||
21 | depends on SH_DMA | ||
22 | bool "Override default number of maximum DMA channels" | ||
23 | help | ||
24 | This allows you to forcibly update the maximum number of supported | ||
25 | DMA channels for a given board. If this is unset, this will default | ||
26 | to the number of channels that the on-chip DMAC has. | ||
27 | |||
28 | config NR_DMA_CHANNELS | ||
29 | int "Maximum number of DMA channels" | ||
30 | depends on SH_DMA && NR_DMA_CHANNELS_BOOL | ||
31 | default NR_ONCHIP_DMA_CHANNELS | ||
32 | help | ||
33 | This allows you to specify the maximum number of DMA channels to | ||
34 | support. Setting this to a higher value allows for cascading DMACs | ||
35 | with additional channels. | ||
36 | |||
37 | config DMA_PAGE_OPS | ||
38 | bool "Use DMAC for page copy/clear" | ||
39 | depends on SH_DMA && BROKEN | ||
40 | help | ||
41 | Selecting this option will use a dual-address mode configured channel | ||
42 | in the SH DMAC for copy_page()/clear_page(). Primarily a performance | ||
43 | hack. | ||
44 | |||
45 | config DMA_PAGE_OPS_CHANNEL | ||
46 | depends on DMA_PAGE_OPS | ||
47 | int "DMA channel for sh memory-manager page copy/clear" | ||
48 | default "3" | ||
49 | help | ||
50 | This allows the specification of the dual address dma channel, | ||
51 | in case channel 3 is unavailable. On the SH4, channels 1,2, and 3 | ||
52 | are dual-address capable. | ||
53 | |||
54 | endmenu | ||
55 | |||
diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile new file mode 100644 index 000000000000..065d4c90970e --- /dev/null +++ b/arch/sh/drivers/dma/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for the SuperH DMA specific kernel interface routines under Linux. | ||
3 | # | ||
4 | |||
5 | obj-y += dma-api.o dma-isa.o | ||
6 | obj-$(CONFIG_SYSFS) += dma-sysfs.o | ||
7 | obj-$(CONFIG_SH_DMA) += dma-sh.o | ||
8 | obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o | ||
9 | |||
diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c new file mode 100644 index 000000000000..96e3036ec2bb --- /dev/null +++ b/arch/sh/drivers/dma/dma-api.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/dma/dma-api.c | ||
3 | * | ||
4 | * SuperH-specific DMA management API | ||
5 | * | ||
6 | * Copyright (C) 2003, 2004 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/list.h> | ||
18 | #include <asm/dma.h> | ||
19 | |||
20 | DEFINE_SPINLOCK(dma_spin_lock); | ||
21 | static LIST_HEAD(registered_dmac_list); | ||
22 | |||
23 | /* | ||
24 | * A brief note about the reasons for this API as it stands. | ||
25 | * | ||
26 | * For starters, the old ISA DMA API didn't work for us for a number of | ||
27 | * reasons, for one, the vast majority of channels on the SH DMAC are | ||
28 | * dual-address mode only, and both the new and the old DMA APIs are after the | ||
29 | * concept of managing a DMA buffer, which doesn't overly fit this model very | ||
30 | * well. In addition to which, the new API is largely geared at IOMMUs and | ||
31 | * GARTs, and doesn't even support the channel notion very well. | ||
32 | * | ||
33 | * The other thing that's a marginal issue, is the sheer number of random DMA | ||
34 | * engines that are present (ie, in boards like the Dreamcast), some of which | ||
35 | * cascade off of the SH DMAC, and others do not. As such, there was a real | ||
36 | * need for a scalable subsystem that could deal with both single and | ||
37 | * dual-address mode usage, in addition to interoperating with cascaded DMACs. | ||
38 | * | ||
39 | * There really isn't any reason why this needs to be SH specific, though I'm | ||
40 | * not aware of too many other processors (with the exception of some MIPS) | ||
41 | * that have the same concept of a dual address mode, or any real desire to | ||
42 | * actually make use of the DMAC even if such a subsystem were exposed | ||
43 | * elsewhere. | ||
44 | * | ||
45 | * The idea for this was derived from the ARM port, which acted as an excellent | ||
46 | * reference when trying to address these issues. | ||
47 | * | ||
48 | * It should also be noted that the decision to add Yet Another DMA API(tm) to | ||
49 | * the kernel wasn't made easily, and was only decided upon after conferring | ||
50 | * with jejb with regards to the state of the old and new APIs as they applied | ||
51 | * to these circumstances. Philip Blundell was also a great help in figuring | ||
52 | * out some single-address mode DMA semantics that were otherwise rather | ||
53 | * confusing. | ||
54 | */ | ||
55 | |||
56 | struct dma_info *get_dma_info(unsigned int chan) | ||
57 | { | ||
58 | struct list_head *pos, *tmp; | ||
59 | unsigned int total = 0; | ||
60 | |||
61 | /* | ||
62 | * Look for each DMAC's range to determine who the owner of | ||
63 | * the channel is. | ||
64 | */ | ||
65 | list_for_each_safe(pos, tmp, ®istered_dmac_list) { | ||
66 | struct dma_info *info = list_entry(pos, struct dma_info, list); | ||
67 | |||
68 | total += info->nr_channels; | ||
69 | if (chan > total) | ||
70 | continue; | ||
71 | |||
72 | return info; | ||
73 | } | ||
74 | |||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | struct dma_channel *get_dma_channel(unsigned int chan) | ||
79 | { | ||
80 | struct dma_info *info = get_dma_info(chan); | ||
81 | |||
82 | if (!info) | ||
83 | return ERR_PTR(-EINVAL); | ||
84 | |||
85 | return info->channels + chan; | ||
86 | } | ||
87 | |||
88 | int get_dma_residue(unsigned int chan) | ||
89 | { | ||
90 | struct dma_info *info = get_dma_info(chan); | ||
91 | struct dma_channel *channel = &info->channels[chan]; | ||
92 | |||
93 | if (info->ops->get_residue) | ||
94 | return info->ops->get_residue(channel); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | int request_dma(unsigned int chan, const char *dev_id) | ||
100 | { | ||
101 | struct dma_info *info = get_dma_info(chan); | ||
102 | struct dma_channel *channel = &info->channels[chan]; | ||
103 | |||
104 | down(&channel->sem); | ||
105 | |||
106 | if (!info->ops || chan >= MAX_DMA_CHANNELS) { | ||
107 | up(&channel->sem); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | atomic_set(&channel->busy, 1); | ||
112 | |||
113 | strlcpy(channel->dev_id, dev_id, sizeof(channel->dev_id)); | ||
114 | |||
115 | up(&channel->sem); | ||
116 | |||
117 | if (info->ops->request) | ||
118 | return info->ops->request(channel); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | void free_dma(unsigned int chan) | ||
124 | { | ||
125 | struct dma_info *info = get_dma_info(chan); | ||
126 | struct dma_channel *channel = &info->channels[chan]; | ||
127 | |||
128 | if (info->ops->free) | ||
129 | info->ops->free(channel); | ||
130 | |||
131 | atomic_set(&channel->busy, 0); | ||
132 | } | ||
133 | |||
134 | void dma_wait_for_completion(unsigned int chan) | ||
135 | { | ||
136 | struct dma_info *info = get_dma_info(chan); | ||
137 | struct dma_channel *channel = &info->channels[chan]; | ||
138 | |||
139 | if (channel->flags & DMA_TEI_CAPABLE) { | ||
140 | wait_event(channel->wait_queue, | ||
141 | (info->ops->get_residue(channel) == 0)); | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | while (info->ops->get_residue(channel)) | ||
146 | cpu_relax(); | ||
147 | } | ||
148 | |||
149 | void dma_configure_channel(unsigned int chan, unsigned long flags) | ||
150 | { | ||
151 | struct dma_info *info = get_dma_info(chan); | ||
152 | struct dma_channel *channel = &info->channels[chan]; | ||
153 | |||
154 | if (info->ops->configure) | ||
155 | info->ops->configure(channel, flags); | ||
156 | } | ||
157 | |||
158 | int dma_xfer(unsigned int chan, unsigned long from, | ||
159 | unsigned long to, size_t size, unsigned int mode) | ||
160 | { | ||
161 | struct dma_info *info = get_dma_info(chan); | ||
162 | struct dma_channel *channel = &info->channels[chan]; | ||
163 | |||
164 | channel->sar = from; | ||
165 | channel->dar = to; | ||
166 | channel->count = size; | ||
167 | channel->mode = mode; | ||
168 | |||
169 | return info->ops->xfer(channel); | ||
170 | } | ||
171 | |||
172 | #ifdef CONFIG_PROC_FS | ||
173 | static int dma_read_proc(char *buf, char **start, off_t off, | ||
174 | int len, int *eof, void *data) | ||
175 | { | ||
176 | struct list_head *pos, *tmp; | ||
177 | char *p = buf; | ||
178 | |||
179 | if (list_empty(®istered_dmac_list)) | ||
180 | return 0; | ||
181 | |||
182 | /* | ||
183 | * Iterate over each registered DMAC | ||
184 | */ | ||
185 | list_for_each_safe(pos, tmp, ®istered_dmac_list) { | ||
186 | struct dma_info *info = list_entry(pos, struct dma_info, list); | ||
187 | int i; | ||
188 | |||
189 | /* | ||
190 | * Iterate over each channel | ||
191 | */ | ||
192 | for (i = 0; i < info->nr_channels; i++) { | ||
193 | struct dma_channel *channel = info->channels + i; | ||
194 | |||
195 | if (!(channel->flags & DMA_CONFIGURED)) | ||
196 | continue; | ||
197 | |||
198 | p += sprintf(p, "%2d: %14s %s\n", i, | ||
199 | info->name, channel->dev_id); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | return p - buf; | ||
204 | } | ||
205 | #endif | ||
206 | |||
207 | |||
208 | int __init register_dmac(struct dma_info *info) | ||
209 | { | ||
210 | int i; | ||
211 | |||
212 | INIT_LIST_HEAD(&info->list); | ||
213 | |||
214 | printk(KERN_INFO "DMA: Registering %s handler (%d channel%s).\n", | ||
215 | info->name, info->nr_channels, | ||
216 | info->nr_channels > 1 ? "s" : ""); | ||
217 | |||
218 | BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); | ||
219 | |||
220 | /* | ||
221 | * Don't touch pre-configured channels | ||
222 | */ | ||
223 | if (!(info->flags & DMAC_CHANNELS_CONFIGURED)) { | ||
224 | unsigned int size; | ||
225 | |||
226 | size = sizeof(struct dma_channel) * info->nr_channels; | ||
227 | |||
228 | info->channels = kmalloc(size, GFP_KERNEL); | ||
229 | if (!info->channels) | ||
230 | return -ENOMEM; | ||
231 | |||
232 | memset(info->channels, 0, size); | ||
233 | } | ||
234 | |||
235 | for (i = 0; i < info->nr_channels; i++) { | ||
236 | struct dma_channel *chan = info->channels + i; | ||
237 | |||
238 | chan->chan = i; | ||
239 | |||
240 | memcpy(chan->dev_id, "Unused", 7); | ||
241 | |||
242 | if (info->flags & DMAC_CHANNELS_TEI_CAPABLE) | ||
243 | chan->flags |= DMA_TEI_CAPABLE; | ||
244 | |||
245 | init_MUTEX(&chan->sem); | ||
246 | init_waitqueue_head(&chan->wait_queue); | ||
247 | |||
248 | #ifdef CONFIG_SYSFS | ||
249 | dma_create_sysfs_files(chan); | ||
250 | #endif | ||
251 | } | ||
252 | |||
253 | list_add(&info->list, ®istered_dmac_list); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | void __exit unregister_dmac(struct dma_info *info) | ||
259 | { | ||
260 | if (!(info->flags & DMAC_CHANNELS_CONFIGURED)) | ||
261 | kfree(info->channels); | ||
262 | |||
263 | list_del(&info->list); | ||
264 | } | ||
265 | |||
266 | static int __init dma_api_init(void) | ||
267 | { | ||
268 | printk("DMA: Registering DMA API.\n"); | ||
269 | |||
270 | #ifdef CONFIG_PROC_FS | ||
271 | create_proc_read_entry("dma", 0, 0, dma_read_proc, 0); | ||
272 | #endif | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | subsys_initcall(dma_api_init); | ||
278 | |||
279 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); | ||
280 | MODULE_DESCRIPTION("DMA API for SuperH"); | ||
281 | MODULE_LICENSE("GPL"); | ||
282 | |||
283 | EXPORT_SYMBOL(request_dma); | ||
284 | EXPORT_SYMBOL(free_dma); | ||
285 | EXPORT_SYMBOL(register_dmac); | ||
286 | EXPORT_SYMBOL(get_dma_residue); | ||
287 | EXPORT_SYMBOL(get_dma_info); | ||
288 | EXPORT_SYMBOL(get_dma_channel); | ||
289 | EXPORT_SYMBOL(dma_xfer); | ||
290 | EXPORT_SYMBOL(dma_wait_for_completion); | ||
291 | EXPORT_SYMBOL(dma_configure_channel); | ||
292 | |||
diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c new file mode 100644 index 000000000000..231e3f6fb28f --- /dev/null +++ b/arch/sh/drivers/dma/dma-g2.c | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/dma/dma-g2.c | ||
3 | * | ||
4 | * G2 bus DMA support | ||
5 | * | ||
6 | * Copyright (C) 2003, 2004 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | |||
17 | #include <asm/mach/sysasic.h> | ||
18 | #include <asm/mach/dma.h> | ||
19 | #include <asm/dma.h> | ||
20 | |||
21 | struct g2_channel { | ||
22 | unsigned long g2_addr; /* G2 bus address */ | ||
23 | unsigned long root_addr; /* Root bus (SH-4) address */ | ||
24 | unsigned long size; /* Size (in bytes), 32-byte aligned */ | ||
25 | unsigned long direction; /* Transfer direction */ | ||
26 | unsigned long ctrl; /* Transfer control */ | ||
27 | unsigned long chan_enable; /* Channel enable */ | ||
28 | unsigned long xfer_enable; /* Transfer enable */ | ||
29 | unsigned long xfer_stat; /* Transfer status */ | ||
30 | } __attribute__ ((aligned(32))); | ||
31 | |||
32 | struct g2_status { | ||
33 | unsigned long g2_addr; | ||
34 | unsigned long root_addr; | ||
35 | unsigned long size; | ||
36 | unsigned long status; | ||
37 | } __attribute__ ((aligned(16))); | ||
38 | |||
39 | struct g2_dma_info { | ||
40 | struct g2_channel channel[G2_NR_DMA_CHANNELS]; | ||
41 | unsigned long pad1[G2_NR_DMA_CHANNELS]; | ||
42 | unsigned long wait_state; | ||
43 | unsigned long pad2[10]; | ||
44 | unsigned long magic; | ||
45 | struct g2_status status[G2_NR_DMA_CHANNELS]; | ||
46 | } __attribute__ ((aligned(256))); | ||
47 | |||
48 | static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800; | ||
49 | |||
50 | static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
51 | { | ||
52 | /* FIXME: Do some meaningful completion work here.. */ | ||
53 | return IRQ_HANDLED; | ||
54 | } | ||
55 | |||
56 | static struct irqaction g2_dma_irq = { | ||
57 | .name = "g2 DMA handler", | ||
58 | .handler = g2_dma_interrupt, | ||
59 | .flags = SA_INTERRUPT, | ||
60 | }; | ||
61 | |||
62 | static int g2_enable_dma(struct dma_channel *chan) | ||
63 | { | ||
64 | unsigned int chan_nr = chan->chan; | ||
65 | |||
66 | g2_dma->channel[chan_nr].chan_enable = 1; | ||
67 | g2_dma->channel[chan_nr].xfer_enable = 1; | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int g2_disable_dma(struct dma_channel *chan) | ||
73 | { | ||
74 | unsigned int chan_nr = chan->chan; | ||
75 | |||
76 | g2_dma->channel[chan_nr].chan_enable = 0; | ||
77 | g2_dma->channel[chan_nr].xfer_enable = 0; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int g2_xfer_dma(struct dma_channel *chan) | ||
83 | { | ||
84 | unsigned int chan_nr = chan->chan; | ||
85 | |||
86 | if (chan->sar & 31) { | ||
87 | printk("g2dma: unaligned source 0x%lx\n", chan->sar); | ||
88 | return -EINVAL; | ||
89 | } | ||
90 | |||
91 | if (chan->dar & 31) { | ||
92 | printk("g2dma: unaligned dest 0x%lx\n", chan->dar); | ||
93 | return -EINVAL; | ||
94 | } | ||
95 | |||
96 | /* Align the count */ | ||
97 | if (chan->count & 31) | ||
98 | chan->count = (chan->count + (32 - 1)) & ~(32 - 1); | ||
99 | |||
100 | /* Fixup destination */ | ||
101 | chan->dar += 0xa0800000; | ||
102 | |||
103 | /* Fixup direction */ | ||
104 | chan->mode = !chan->mode; | ||
105 | |||
106 | flush_icache_range((unsigned long)chan->sar, chan->count); | ||
107 | |||
108 | g2_disable_dma(chan); | ||
109 | |||
110 | g2_dma->channel[chan_nr].g2_addr = chan->dar & 0x1fffffe0; | ||
111 | g2_dma->channel[chan_nr].root_addr = chan->sar & 0x1fffffe0; | ||
112 | g2_dma->channel[chan_nr].size = (chan->count & ~31) | 0x80000000; | ||
113 | g2_dma->channel[chan_nr].direction = chan->mode; | ||
114 | |||
115 | /* | ||
116 | * bit 0 - ??? | ||
117 | * bit 1 - if set, generate a hardware event on transfer completion | ||
118 | * bit 2 - ??? something to do with suspend? | ||
119 | */ | ||
120 | g2_dma->channel[chan_nr].ctrl = 5; /* ?? */ | ||
121 | |||
122 | g2_enable_dma(chan); | ||
123 | |||
124 | /* debug cruft */ | ||
125 | pr_debug("count, sar, dar, mode, ctrl, chan, xfer: %ld, 0x%08lx, " | ||
126 | "0x%08lx, %ld, %ld, %ld, %ld\n", | ||
127 | g2_dma->channel[chan_nr].size, | ||
128 | g2_dma->channel[chan_nr].root_addr, | ||
129 | g2_dma->channel[chan_nr].g2_addr, | ||
130 | g2_dma->channel[chan_nr].direction, | ||
131 | g2_dma->channel[chan_nr].ctrl, | ||
132 | g2_dma->channel[chan_nr].chan_enable, | ||
133 | g2_dma->channel[chan_nr].xfer_enable); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static struct dma_ops g2_dma_ops = { | ||
139 | .xfer = g2_xfer_dma, | ||
140 | }; | ||
141 | |||
142 | static struct dma_info g2_dma_info = { | ||
143 | .name = "G2 DMA", | ||
144 | .nr_channels = 4, | ||
145 | .ops = &g2_dma_ops, | ||
146 | .flags = DMAC_CHANNELS_TEI_CAPABLE, | ||
147 | }; | ||
148 | |||
149 | static int __init g2_dma_init(void) | ||
150 | { | ||
151 | setup_irq(HW_EVENT_G2_DMA, &g2_dma_irq); | ||
152 | |||
153 | /* Magic */ | ||
154 | g2_dma->wait_state = 27; | ||
155 | g2_dma->magic = 0x4659404f; | ||
156 | |||
157 | return register_dmac(&g2_dma_info); | ||
158 | } | ||
159 | |||
160 | static void __exit g2_dma_exit(void) | ||
161 | { | ||
162 | free_irq(HW_EVENT_G2_DMA, 0); | ||
163 | } | ||
164 | |||
165 | subsys_initcall(g2_dma_init); | ||
166 | module_exit(g2_dma_exit); | ||
167 | |||
168 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); | ||
169 | MODULE_DESCRIPTION("G2 bus DMA driver"); | ||
170 | MODULE_LICENSE("GPL"); | ||
171 | |||
diff --git a/arch/sh/drivers/dma/dma-isa.c b/arch/sh/drivers/dma/dma-isa.c new file mode 100644 index 000000000000..1c9bc45b8bcb --- /dev/null +++ b/arch/sh/drivers/dma/dma-isa.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/dma/dma-isa.c | ||
3 | * | ||
4 | * Generic ISA DMA wrapper for SH DMA API | ||
5 | * | ||
6 | * Copyright (C) 2003, 2004 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <asm/dma.h> | ||
15 | |||
16 | /* | ||
17 | * This implements a small wrapper set to make code using the old ISA DMA API | ||
18 | * work with the SH DMA API. Since most of the work in the new API happens | ||
19 | * at ops->xfer() time, we simply use the various set_dma_xxx() routines to | ||
20 | * fill in per-channel info, and then hand hand this off to ops->xfer() at | ||
21 | * enable_dma() time. | ||
22 | * | ||
23 | * For channels that are doing on-demand data transfer via cascading, the | ||
24 | * channel itself will still need to be configured through the new API. As | ||
25 | * such, this code is meant for only the simplest of tasks (and shouldn't be | ||
26 | * used in any new drivers at all). | ||
27 | * | ||
28 | * It should also be noted that various functions here are labelled as | ||
29 | * being deprecated. This is due to the fact that the ops->xfer() method is | ||
30 | * the preferred way of doing things (as well as just grabbing the spinlock | ||
31 | * directly). As such, any users of this interface will be warned rather | ||
32 | * loudly. | ||
33 | */ | ||
34 | |||
35 | unsigned long __deprecated claim_dma_lock(void) | ||
36 | { | ||
37 | unsigned long flags; | ||
38 | |||
39 | spin_lock_irqsave(&dma_spin_lock, flags); | ||
40 | |||
41 | return flags; | ||
42 | } | ||
43 | EXPORT_SYMBOL(claim_dma_lock); | ||
44 | |||
45 | void __deprecated release_dma_lock(unsigned long flags) | ||
46 | { | ||
47 | spin_unlock_irqrestore(&dma_spin_lock, flags); | ||
48 | } | ||
49 | EXPORT_SYMBOL(release_dma_lock); | ||
50 | |||
51 | void __deprecated disable_dma(unsigned int chan) | ||
52 | { | ||
53 | /* Nothing */ | ||
54 | } | ||
55 | EXPORT_SYMBOL(disable_dma); | ||
56 | |||
57 | void __deprecated enable_dma(unsigned int chan) | ||
58 | { | ||
59 | struct dma_info *info = get_dma_info(chan); | ||
60 | struct dma_channel *channel = &info->channels[chan]; | ||
61 | |||
62 | info->ops->xfer(channel); | ||
63 | } | ||
64 | EXPORT_SYMBOL(enable_dma); | ||
65 | |||
66 | void clear_dma_ff(unsigned int chan) | ||
67 | { | ||
68 | /* Nothing */ | ||
69 | } | ||
70 | EXPORT_SYMBOL(clear_dma_ff); | ||
71 | |||
72 | void set_dma_mode(unsigned int chan, char mode) | ||
73 | { | ||
74 | struct dma_info *info = get_dma_info(chan); | ||
75 | struct dma_channel *channel = &info->channels[chan]; | ||
76 | |||
77 | channel->mode = mode; | ||
78 | } | ||
79 | EXPORT_SYMBOL(set_dma_mode); | ||
80 | |||
81 | void set_dma_addr(unsigned int chan, unsigned int addr) | ||
82 | { | ||
83 | struct dma_info *info = get_dma_info(chan); | ||
84 | struct dma_channel *channel = &info->channels[chan]; | ||
85 | |||
86 | /* | ||
87 | * Single address mode is the only thing supported through | ||
88 | * this interface. | ||
89 | */ | ||
90 | if ((channel->mode & DMA_MODE_MASK) == DMA_MODE_READ) { | ||
91 | channel->sar = addr; | ||
92 | } else { | ||
93 | channel->dar = addr; | ||
94 | } | ||
95 | } | ||
96 | EXPORT_SYMBOL(set_dma_addr); | ||
97 | |||
98 | void set_dma_count(unsigned int chan, unsigned int count) | ||
99 | { | ||
100 | struct dma_info *info = get_dma_info(chan); | ||
101 | struct dma_channel *channel = &info->channels[chan]; | ||
102 | |||
103 | channel->count = count; | ||
104 | } | ||
105 | EXPORT_SYMBOL(set_dma_count); | ||
106 | |||
diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c new file mode 100644 index 000000000000..2e1d58f2d1b9 --- /dev/null +++ b/arch/sh/drivers/dma/dma-pvr2.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * arch/sh/boards/dreamcast/dma-pvr2.c | ||
3 | * | ||
4 | * NEC PowerVR 2 (Dreamcast) DMA support | ||
5 | * | ||
6 | * Copyright (C) 2003, 2004 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <asm/mach/sysasic.h> | ||
17 | #include <asm/mach/dma.h> | ||
18 | #include <asm/dma.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | static unsigned int xfer_complete = 0; | ||
22 | static int count = 0; | ||
23 | |||
24 | static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
25 | { | ||
26 | if (get_dma_residue(PVR2_CASCADE_CHAN)) { | ||
27 | printk(KERN_WARNING "DMA: SH DMAC did not complete transfer " | ||
28 | "on channel %d, waiting..\n", PVR2_CASCADE_CHAN); | ||
29 | dma_wait_for_completion(PVR2_CASCADE_CHAN); | ||
30 | } | ||
31 | |||
32 | if (count++ < 10) | ||
33 | pr_debug("Got a pvr2 dma interrupt for channel %d\n", | ||
34 | irq - HW_EVENT_PVR2_DMA); | ||
35 | |||
36 | xfer_complete = 1; | ||
37 | |||
38 | return IRQ_HANDLED; | ||
39 | } | ||
40 | |||
41 | static int pvr2_request_dma(struct dma_channel *chan) | ||
42 | { | ||
43 | if (ctrl_inl(PVR2_DMA_MODE) != 0) | ||
44 | return -EBUSY; | ||
45 | |||
46 | ctrl_outl(0, PVR2_DMA_LMMODE0); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static int pvr2_get_dma_residue(struct dma_channel *chan) | ||
52 | { | ||
53 | return xfer_complete == 0; | ||
54 | } | ||
55 | |||
56 | static int pvr2_xfer_dma(struct dma_channel *chan) | ||
57 | { | ||
58 | if (chan->sar || !chan->dar) | ||
59 | return -EINVAL; | ||
60 | |||
61 | xfer_complete = 0; | ||
62 | |||
63 | ctrl_outl(chan->dar, PVR2_DMA_ADDR); | ||
64 | ctrl_outl(chan->count, PVR2_DMA_COUNT); | ||
65 | ctrl_outl(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static struct irqaction pvr2_dma_irq = { | ||
71 | .name = "pvr2 DMA handler", | ||
72 | .handler = pvr2_dma_interrupt, | ||
73 | .flags = SA_INTERRUPT, | ||
74 | }; | ||
75 | |||
76 | static struct dma_ops pvr2_dma_ops = { | ||
77 | .request = pvr2_request_dma, | ||
78 | .get_residue = pvr2_get_dma_residue, | ||
79 | .xfer = pvr2_xfer_dma, | ||
80 | }; | ||
81 | |||
82 | static struct dma_info pvr2_dma_info = { | ||
83 | .name = "PowerVR 2 DMA", | ||
84 | .nr_channels = 1, | ||
85 | .ops = &pvr2_dma_ops, | ||
86 | .flags = DMAC_CHANNELS_TEI_CAPABLE, | ||
87 | }; | ||
88 | |||
89 | static int __init pvr2_dma_init(void) | ||
90 | { | ||
91 | setup_irq(HW_EVENT_PVR2_DMA, &pvr2_dma_irq); | ||
92 | request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade"); | ||
93 | |||
94 | return register_dmac(&pvr2_dma_info); | ||
95 | } | ||
96 | |||
97 | static void __exit pvr2_dma_exit(void) | ||
98 | { | ||
99 | free_dma(PVR2_CASCADE_CHAN); | ||
100 | free_irq(HW_EVENT_PVR2_DMA, 0); | ||
101 | } | ||
102 | |||
103 | subsys_initcall(pvr2_dma_init); | ||
104 | module_exit(pvr2_dma_exit); | ||
105 | |||
106 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); | ||
107 | MODULE_DESCRIPTION("NEC PowerVR 2 DMA driver"); | ||
108 | MODULE_LICENSE("GPL"); | ||
109 | |||
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c new file mode 100644 index 000000000000..31dacd4444b2 --- /dev/null +++ b/arch/sh/drivers/dma/dma-sh.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/dma/dma-sh.c | ||
3 | * | ||
4 | * SuperH On-chip DMAC Support | ||
5 | * | ||
6 | * Copyright (C) 2000 Takashi YOSHII | ||
7 | * Copyright (C) 2003, 2004 Paul Mundt | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <asm/signal.h> | ||
20 | #include <asm/irq.h> | ||
21 | #include <asm/dma.h> | ||
22 | #include <asm/io.h> | ||
23 | #include "dma-sh.h" | ||
24 | |||
25 | /* | ||
26 | * The SuperH DMAC supports a number of transmit sizes, we list them here, | ||
27 | * with their respective values as they appear in the CHCR registers. | ||
28 | * | ||
29 | * Defaults to a 64-bit transfer size. | ||
30 | */ | ||
31 | enum { | ||
32 | XMIT_SZ_64BIT, | ||
33 | XMIT_SZ_8BIT, | ||
34 | XMIT_SZ_16BIT, | ||
35 | XMIT_SZ_32BIT, | ||
36 | XMIT_SZ_256BIT, | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * The DMA count is defined as the number of bytes to transfer. | ||
41 | */ | ||
42 | static unsigned int ts_shift[] = { | ||
43 | [XMIT_SZ_64BIT] = 3, | ||
44 | [XMIT_SZ_8BIT] = 0, | ||
45 | [XMIT_SZ_16BIT] = 1, | ||
46 | [XMIT_SZ_32BIT] = 2, | ||
47 | [XMIT_SZ_256BIT] = 5, | ||
48 | }; | ||
49 | |||
50 | static inline unsigned int get_dmte_irq(unsigned int chan) | ||
51 | { | ||
52 | unsigned int irq; | ||
53 | |||
54 | /* | ||
55 | * Normally we could just do DMTE0_IRQ + chan outright, though in the | ||
56 | * case of the 7751R, the DMTE IRQs for channels > 4 start right above | ||
57 | * the SCIF | ||
58 | */ | ||
59 | |||
60 | if (chan < 4) { | ||
61 | irq = DMTE0_IRQ + chan; | ||
62 | } else { | ||
63 | irq = DMTE4_IRQ + chan - 4; | ||
64 | } | ||
65 | |||
66 | return irq; | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * We determine the correct shift size based off of the CHCR transmit size | ||
71 | * for the given channel. Since we know that it will take: | ||
72 | * | ||
73 | * info->count >> ts_shift[transmit_size] | ||
74 | * | ||
75 | * iterations to complete the transfer. | ||
76 | */ | ||
77 | static inline unsigned int calc_xmit_shift(struct dma_channel *chan) | ||
78 | { | ||
79 | u32 chcr = ctrl_inl(CHCR[chan->chan]); | ||
80 | |||
81 | chcr >>= 4; | ||
82 | |||
83 | return ts_shift[chcr & 0x0007]; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * The transfer end interrupt must read the chcr register to end the | ||
88 | * hardware interrupt active condition. | ||
89 | * Besides that it needs to waken any waiting process, which should handle | ||
90 | * setting up the next transfer. | ||
91 | */ | ||
92 | static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs) | ||
93 | { | ||
94 | struct dma_channel *chan = (struct dma_channel *)dev_id; | ||
95 | u32 chcr; | ||
96 | |||
97 | chcr = ctrl_inl(CHCR[chan->chan]); | ||
98 | |||
99 | if (!(chcr & CHCR_TE)) | ||
100 | return IRQ_NONE; | ||
101 | |||
102 | chcr &= ~(CHCR_IE | CHCR_DE); | ||
103 | ctrl_outl(chcr, CHCR[chan->chan]); | ||
104 | |||
105 | wake_up(&chan->wait_queue); | ||
106 | |||
107 | return IRQ_HANDLED; | ||
108 | } | ||
109 | |||
110 | static int sh_dmac_request_dma(struct dma_channel *chan) | ||
111 | { | ||
112 | return request_irq(get_dmte_irq(chan->chan), dma_tei, | ||
113 | SA_INTERRUPT, "DMAC Transfer End", chan); | ||
114 | } | ||
115 | |||
116 | static void sh_dmac_free_dma(struct dma_channel *chan) | ||
117 | { | ||
118 | free_irq(get_dmte_irq(chan->chan), chan); | ||
119 | } | ||
120 | |||
121 | static void sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr) | ||
122 | { | ||
123 | if (!chcr) | ||
124 | chcr = RS_DUAL; | ||
125 | |||
126 | ctrl_outl(chcr, CHCR[chan->chan]); | ||
127 | |||
128 | chan->flags |= DMA_CONFIGURED; | ||
129 | } | ||
130 | |||
131 | static void sh_dmac_enable_dma(struct dma_channel *chan) | ||
132 | { | ||
133 | int irq = get_dmte_irq(chan->chan); | ||
134 | u32 chcr; | ||
135 | |||
136 | chcr = ctrl_inl(CHCR[chan->chan]); | ||
137 | chcr |= CHCR_DE | CHCR_IE; | ||
138 | ctrl_outl(chcr, CHCR[chan->chan]); | ||
139 | |||
140 | enable_irq(irq); | ||
141 | } | ||
142 | |||
143 | static void sh_dmac_disable_dma(struct dma_channel *chan) | ||
144 | { | ||
145 | int irq = get_dmte_irq(chan->chan); | ||
146 | u32 chcr; | ||
147 | |||
148 | disable_irq(irq); | ||
149 | |||
150 | chcr = ctrl_inl(CHCR[chan->chan]); | ||
151 | chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE); | ||
152 | ctrl_outl(chcr, CHCR[chan->chan]); | ||
153 | } | ||
154 | |||
155 | static int sh_dmac_xfer_dma(struct dma_channel *chan) | ||
156 | { | ||
157 | /* | ||
158 | * If we haven't pre-configured the channel with special flags, use | ||
159 | * the defaults. | ||
160 | */ | ||
161 | if (!(chan->flags & DMA_CONFIGURED)) | ||
162 | sh_dmac_configure_channel(chan, 0); | ||
163 | |||
164 | sh_dmac_disable_dma(chan); | ||
165 | |||
166 | /* | ||
167 | * Single-address mode usage note! | ||
168 | * | ||
169 | * It's important that we don't accidentally write any value to SAR/DAR | ||
170 | * (this includes 0) that hasn't been directly specified by the user if | ||
171 | * we're in single-address mode. | ||
172 | * | ||
173 | * In this case, only one address can be defined, anything else will | ||
174 | * result in a DMA address error interrupt (at least on the SH-4), | ||
175 | * which will subsequently halt the transfer. | ||
176 | * | ||
177 | * Channel 2 on the Dreamcast is a special case, as this is used for | ||
178 | * cascading to the PVR2 DMAC. In this case, we still need to write | ||
179 | * SAR and DAR, regardless of value, in order for cascading to work. | ||
180 | */ | ||
181 | if (chan->sar || (mach_is_dreamcast() && chan->chan == 2)) | ||
182 | ctrl_outl(chan->sar, SAR[chan->chan]); | ||
183 | if (chan->dar || (mach_is_dreamcast() && chan->chan == 2)) | ||
184 | ctrl_outl(chan->dar, DAR[chan->chan]); | ||
185 | |||
186 | ctrl_outl(chan->count >> calc_xmit_shift(chan), DMATCR[chan->chan]); | ||
187 | |||
188 | sh_dmac_enable_dma(chan); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int sh_dmac_get_dma_residue(struct dma_channel *chan) | ||
194 | { | ||
195 | if (!(ctrl_inl(CHCR[chan->chan]) & CHCR_DE)) | ||
196 | return 0; | ||
197 | |||
198 | return ctrl_inl(DMATCR[chan->chan]) << calc_xmit_shift(chan); | ||
199 | } | ||
200 | |||
201 | #if defined(CONFIG_CPU_SH4) | ||
202 | static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs) | ||
203 | { | ||
204 | unsigned long dmaor = ctrl_inl(DMAOR); | ||
205 | |||
206 | printk("DMAE: DMAOR=%lx\n", dmaor); | ||
207 | |||
208 | ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_NMIF, DMAOR); | ||
209 | ctrl_outl(ctrl_inl(DMAOR)&~DMAOR_AE, DMAOR); | ||
210 | ctrl_outl(ctrl_inl(DMAOR)|DMAOR_DME, DMAOR); | ||
211 | |||
212 | disable_irq(irq); | ||
213 | |||
214 | return IRQ_HANDLED; | ||
215 | } | ||
216 | #endif | ||
217 | |||
218 | static struct dma_ops sh_dmac_ops = { | ||
219 | .request = sh_dmac_request_dma, | ||
220 | .free = sh_dmac_free_dma, | ||
221 | .get_residue = sh_dmac_get_dma_residue, | ||
222 | .xfer = sh_dmac_xfer_dma, | ||
223 | .configure = sh_dmac_configure_channel, | ||
224 | }; | ||
225 | |||
226 | static struct dma_info sh_dmac_info = { | ||
227 | .name = "SuperH DMAC", | ||
228 | .nr_channels = 4, | ||
229 | .ops = &sh_dmac_ops, | ||
230 | .flags = DMAC_CHANNELS_TEI_CAPABLE, | ||
231 | }; | ||
232 | |||
233 | static int __init sh_dmac_init(void) | ||
234 | { | ||
235 | struct dma_info *info = &sh_dmac_info; | ||
236 | int i; | ||
237 | |||
238 | #ifdef CONFIG_CPU_SH4 | ||
239 | make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY); | ||
240 | i = request_irq(DMAE_IRQ, dma_err, SA_INTERRUPT, "DMAC Address Error", 0); | ||
241 | if (i < 0) | ||
242 | return i; | ||
243 | #endif | ||
244 | |||
245 | for (i = 0; i < info->nr_channels; i++) { | ||
246 | int irq = get_dmte_irq(i); | ||
247 | |||
248 | make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY); | ||
249 | } | ||
250 | |||
251 | ctrl_outl(0x8000 | DMAOR_DME, DMAOR); | ||
252 | |||
253 | return register_dmac(info); | ||
254 | } | ||
255 | |||
256 | static void __exit sh_dmac_exit(void) | ||
257 | { | ||
258 | #ifdef CONFIG_CPU_SH4 | ||
259 | free_irq(DMAE_IRQ, 0); | ||
260 | #endif | ||
261 | } | ||
262 | |||
263 | subsys_initcall(sh_dmac_init); | ||
264 | module_exit(sh_dmac_exit); | ||
265 | |||
266 | MODULE_LICENSE("GPL"); | ||
267 | |||
diff --git a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h new file mode 100644 index 000000000000..dd9d547539a2 --- /dev/null +++ b/arch/sh/drivers/dma/dma-sh.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/dma/dma-sh.h | ||
3 | * | ||
4 | * Copyright (C) 2000 Takashi YOSHII | ||
5 | * Copyright (C) 2003 Paul Mundt | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | #ifndef __DMA_SH_H | ||
12 | #define __DMA_SH_H | ||
13 | |||
14 | /* Definitions for the SuperH DMAC */ | ||
15 | #define REQ_L 0x00000000 | ||
16 | #define REQ_E 0x00080000 | ||
17 | #define RACK_H 0x00000000 | ||
18 | #define RACK_L 0x00040000 | ||
19 | #define ACK_R 0x00000000 | ||
20 | #define ACK_W 0x00020000 | ||
21 | #define ACK_H 0x00000000 | ||
22 | #define ACK_L 0x00010000 | ||
23 | #define DM_INC 0x00004000 | ||
24 | #define DM_DEC 0x00008000 | ||
25 | #define SM_INC 0x00001000 | ||
26 | #define SM_DEC 0x00002000 | ||
27 | #define RS_IN 0x00000200 | ||
28 | #define RS_OUT 0x00000300 | ||
29 | #define TM_BURST 0x0000080 | ||
30 | #define TS_8 0x00000010 | ||
31 | #define TS_16 0x00000020 | ||
32 | #define TS_32 0x00000030 | ||
33 | #define TS_64 0x00000000 | ||
34 | #define TS_BLK 0x00000040 | ||
35 | #define CHCR_DE 0x00000001 | ||
36 | #define CHCR_TE 0x00000002 | ||
37 | #define CHCR_IE 0x00000004 | ||
38 | |||
39 | /* Define the default configuration for dual address memory-memory transfer. | ||
40 | * The 0x400 value represents auto-request, external->external. | ||
41 | */ | ||
42 | #define RS_DUAL (DM_INC | SM_INC | 0x400 | TS_32) | ||
43 | |||
44 | #define DMAOR_COD 0x00000008 | ||
45 | #define DMAOR_AE 0x00000004 | ||
46 | #define DMAOR_NMIF 0x00000002 | ||
47 | #define DMAOR_DME 0x00000001 | ||
48 | |||
49 | #define MAX_DMAC_CHANNELS (CONFIG_NR_ONCHIP_DMA_CHANNELS) | ||
50 | |||
51 | #endif /* __DMA_SH_H */ | ||
52 | |||
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c new file mode 100644 index 000000000000..71a6d4e7809f --- /dev/null +++ b/arch/sh/drivers/dma/dma-sysfs.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/dma/dma-sysfs.c | ||
3 | * | ||
4 | * sysfs interface for SH DMA API | ||
5 | * | ||
6 | * Copyright (C) 2004 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/sysdev.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <asm/dma.h> | ||
17 | |||
18 | static struct sysdev_class dma_sysclass = { | ||
19 | set_kset_name("dma"), | ||
20 | }; | ||
21 | |||
22 | EXPORT_SYMBOL(dma_sysclass); | ||
23 | |||
24 | static ssize_t dma_show_devices(struct sys_device *dev, char *buf) | ||
25 | { | ||
26 | ssize_t len = 0; | ||
27 | int i; | ||
28 | |||
29 | for (i = 0; i < MAX_DMA_CHANNELS; i++) { | ||
30 | struct dma_info *info = get_dma_info(i); | ||
31 | struct dma_channel *channel = &info->channels[i]; | ||
32 | |||
33 | len += sprintf(buf + len, "%2d: %14s %s\n", | ||
34 | channel->chan, info->name, | ||
35 | channel->dev_id); | ||
36 | } | ||
37 | |||
38 | return len; | ||
39 | } | ||
40 | |||
41 | static SYSDEV_ATTR(devices, S_IRUGO, dma_show_devices, NULL); | ||
42 | |||
43 | static int __init dma_sysclass_init(void) | ||
44 | { | ||
45 | int ret; | ||
46 | |||
47 | ret = sysdev_class_register(&dma_sysclass); | ||
48 | if (ret == 0) | ||
49 | sysfs_create_file(&dma_sysclass.kset.kobj, &attr_devices.attr); | ||
50 | |||
51 | return ret; | ||
52 | } | ||
53 | |||
54 | postcore_initcall(dma_sysclass_init); | ||
55 | |||
56 | static ssize_t dma_show_dev_id(struct sys_device *dev, char *buf) | ||
57 | { | ||
58 | struct dma_channel *channel = to_dma_channel(dev); | ||
59 | return sprintf(buf, "%s\n", channel->dev_id); | ||
60 | } | ||
61 | |||
62 | static ssize_t dma_store_dev_id(struct sys_device *dev, | ||
63 | const char *buf, size_t count) | ||
64 | { | ||
65 | struct dma_channel *channel = to_dma_channel(dev); | ||
66 | strcpy(channel->dev_id, buf); | ||
67 | return count; | ||
68 | } | ||
69 | |||
70 | static SYSDEV_ATTR(dev_id, S_IRUGO | S_IWUSR, dma_show_dev_id, dma_store_dev_id); | ||
71 | |||
72 | static ssize_t dma_store_config(struct sys_device *dev, | ||
73 | const char *buf, size_t count) | ||
74 | { | ||
75 | struct dma_channel *channel = to_dma_channel(dev); | ||
76 | unsigned long config; | ||
77 | |||
78 | config = simple_strtoul(buf, NULL, 0); | ||
79 | dma_configure_channel(channel->chan, config); | ||
80 | |||
81 | return count; | ||
82 | } | ||
83 | |||
84 | static SYSDEV_ATTR(config, S_IWUSR, NULL, dma_store_config); | ||
85 | |||
86 | static ssize_t dma_show_mode(struct sys_device *dev, char *buf) | ||
87 | { | ||
88 | struct dma_channel *channel = to_dma_channel(dev); | ||
89 | return sprintf(buf, "0x%08x\n", channel->mode); | ||
90 | } | ||
91 | |||
92 | static ssize_t dma_store_mode(struct sys_device *dev, | ||
93 | const char *buf, size_t count) | ||
94 | { | ||
95 | struct dma_channel *channel = to_dma_channel(dev); | ||
96 | channel->mode = simple_strtoul(buf, NULL, 0); | ||
97 | return count; | ||
98 | } | ||
99 | |||
100 | static SYSDEV_ATTR(mode, S_IRUGO | S_IWUSR, dma_show_mode, dma_store_mode); | ||
101 | |||
102 | #define dma_ro_attr(field, fmt) \ | ||
103 | static ssize_t dma_show_##field(struct sys_device *dev, char *buf) \ | ||
104 | { \ | ||
105 | struct dma_channel *channel = to_dma_channel(dev); \ | ||
106 | return sprintf(buf, fmt, channel->field); \ | ||
107 | } \ | ||
108 | static SYSDEV_ATTR(field, S_IRUGO, dma_show_##field, NULL); | ||
109 | |||
110 | dma_ro_attr(count, "0x%08x\n"); | ||
111 | dma_ro_attr(flags, "0x%08lx\n"); | ||
112 | |||
113 | int __init dma_create_sysfs_files(struct dma_channel *chan) | ||
114 | { | ||
115 | struct sys_device *dev = &chan->dev; | ||
116 | int ret; | ||
117 | |||
118 | dev->id = chan->chan; | ||
119 | dev->cls = &dma_sysclass; | ||
120 | |||
121 | ret = sysdev_register(dev); | ||
122 | if (ret) | ||
123 | return ret; | ||
124 | |||
125 | sysdev_create_file(dev, &attr_dev_id); | ||
126 | sysdev_create_file(dev, &attr_count); | ||
127 | sysdev_create_file(dev, &attr_mode); | ||
128 | sysdev_create_file(dev, &attr_flags); | ||
129 | sysdev_create_file(dev, &attr_config); | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig new file mode 100644 index 000000000000..6d1cbbe6745c --- /dev/null +++ b/arch/sh/drivers/pci/Kconfig | |||
@@ -0,0 +1,41 @@ | |||
1 | config PCI | ||
2 | bool "PCI support" | ||
3 | help | ||
4 | Find out whether you have a PCI motherboard. PCI is the name of a | ||
5 | bus system, i.e. the way the CPU talks to the other stuff inside | ||
6 | your box. If you have PCI, say Y, otherwise N. | ||
7 | |||
8 | The PCI-HOWTO, available from | ||
9 | <http://www.tldp.org/docs.html#howto>, contains valuable | ||
10 | information about which PCI hardware does work under Linux and which | ||
11 | doesn't. | ||
12 | |||
13 | config SH_PCIDMA_NONCOHERENT | ||
14 | bool "Cache and PCI noncoherent" | ||
15 | depends on PCI | ||
16 | default y | ||
17 | help | ||
18 | Enable this option if your platform does not have a CPU cache which | ||
19 | remains coherent with PCI DMA. It is safest to say 'Y', although you | ||
20 | will see better performance if you can say 'N', because the PCI DMA | ||
21 | code will not have to flush the CPU's caches. If you have a PCI host | ||
22 | bridge integrated with your SH CPU, refer carefully to the chip specs | ||
23 | to see if you can say 'N' here. Otherwise, leave it as 'Y'. | ||
24 | |||
25 | # This is also board-specific | ||
26 | config PCI_AUTO | ||
27 | bool | ||
28 | depends on PCI | ||
29 | default y | ||
30 | |||
31 | config PCI_AUTO_UPDATE_RESOURCES | ||
32 | bool | ||
33 | depends on PCI_AUTO | ||
34 | default y if !SH_DREAMCAST | ||
35 | help | ||
36 | Selecting this option will cause the PCI auto code to leave your | ||
37 | BAR values alone. Otherwise they will be updated automatically. If | ||
38 | for some reason, you have a board that simply refuses to work | ||
39 | with its resources updated beyond what they are when the device | ||
40 | is powered up, set this to N. Everyone else will want this as Y. | ||
41 | |||
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile new file mode 100644 index 000000000000..365bc16a4a83 --- /dev/null +++ b/arch/sh/drivers/pci/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | # | ||
2 | # Makefile for the PCI specific kernel interface routines under Linux. | ||
3 | # | ||
4 | |||
5 | obj-y += pci.o | ||
6 | obj-$(CONFIG_PCI_AUTO) += pci-auto.o | ||
7 | |||
8 | obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += pci-st40.o | ||
9 | obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o | ||
10 | |||
11 | obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \ | ||
12 | dma-dreamcast.o | ||
13 | obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o | ||
14 | obj-$(CONFIG_SH_BIGSUR) += ops-bigsur.o | ||
15 | obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o | ||
16 | obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o | ||
diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c new file mode 100644 index 000000000000..83de7ef4e7df --- /dev/null +++ b/arch/sh/drivers/pci/dma-dreamcast.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * arch/sh/pci/dma-dreamcast.c | ||
3 | * | ||
4 | * PCI DMA support for the Sega Dreamcast | ||
5 | * | ||
6 | * Copyright (C) 2001, 2002 M. R. Brown | ||
7 | * Copyright (C) 2002, 2003 Paul Mundt | ||
8 | * | ||
9 | * This file originally bore the message (with enclosed-$): | ||
10 | * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp | ||
11 | * Dreamcast PCI: Supports SEGA Broadband Adaptor only. | ||
12 | * | ||
13 | * This file is subject to the terms and conditions of the GNU General Public | ||
14 | * License. See the file "COPYING" in the main directory of this archive | ||
15 | * for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/param.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/dma-mapping.h> | ||
27 | #include <linux/device.h> | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/mach/pci.h> | ||
32 | |||
33 | static int gapspci_dma_used = 0; | ||
34 | |||
35 | void *dreamcast_consistent_alloc(struct device *dev, size_t size, | ||
36 | dma_addr_t *dma_handle, int flag) | ||
37 | { | ||
38 | unsigned long buf; | ||
39 | |||
40 | if (dev && dev->bus != &pci_bus_type) | ||
41 | return NULL; | ||
42 | |||
43 | if (gapspci_dma_used + size > GAPSPCI_DMA_SIZE) | ||
44 | return ERR_PTR(-EINVAL); | ||
45 | |||
46 | buf = GAPSPCI_DMA_BASE + gapspci_dma_used; | ||
47 | |||
48 | gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size); | ||
49 | |||
50 | *dma_handle = (dma_addr_t)buf; | ||
51 | |||
52 | buf = P2SEGADDR(buf); | ||
53 | |||
54 | /* Flush the dcache before we hand off the buffer */ | ||
55 | dma_cache_wback_inv((void *)buf, size); | ||
56 | |||
57 | return (void *)buf; | ||
58 | } | ||
59 | |||
60 | int dreamcast_consistent_free(struct device *dev, size_t size, | ||
61 | void *vaddr, dma_addr_t dma_handle) | ||
62 | { | ||
63 | if (dev && dev->bus != &pci_bus_type) | ||
64 | return -EINVAL; | ||
65 | |||
66 | /* XXX */ | ||
67 | gapspci_dma_used = 0; | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c new file mode 100644 index 000000000000..cf30e2fa51be --- /dev/null +++ b/arch/sh/drivers/pci/fixups-dreamcast.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * arch/sh/pci/fixups-dreamcast.c | ||
3 | * | ||
4 | * PCI fixups for the Sega Dreamcast | ||
5 | * | ||
6 | * Copyright (C) 2001, 2002 M. R. Brown | ||
7 | * Copyright (C) 2002, 2003 Paul Mundt | ||
8 | * | ||
9 | * This file originally bore the message (with enclosed-$): | ||
10 | * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp | ||
11 | * Dreamcast PCI: Supports SEGA Broadband Adaptor only. | ||
12 | * | ||
13 | * This file is subject to the terms and conditions of the GNU General Public | ||
14 | * License. See the file "COPYING" in the main directory of this archive | ||
15 | * for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/param.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/pci.h> | ||
26 | |||
27 | #include <asm/io.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/mach/pci.h> | ||
30 | |||
31 | static void __init gapspci_fixup_resources(struct pci_dev *dev) | ||
32 | { | ||
33 | struct pci_channel *p = board_pci_channels; | ||
34 | |||
35 | printk(KERN_NOTICE "PCI: Fixing up device %s\n", pci_name(dev)); | ||
36 | |||
37 | switch (dev->device) { | ||
38 | case PCI_DEVICE_ID_SEGA_BBA: | ||
39 | /* | ||
40 | * We also assume that dev->devfn == 0 | ||
41 | */ | ||
42 | dev->resource[1].start = p->io_resource->start + 0x100; | ||
43 | dev->resource[1].end = dev->resource[1].start + 0x200 - 1; | ||
44 | break; | ||
45 | default: | ||
46 | printk("PCI: Failed resource fixup\n"); | ||
47 | } | ||
48 | } | ||
49 | |||
50 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources); | ||
51 | |||
52 | void __init pcibios_fixup_bus(struct pci_bus *bus) | ||
53 | { | ||
54 | /* | ||
55 | * We don't have any sub bus to fix up, and this is a rather | ||
56 | * stupid place to put general device fixups. Don't do it. | ||
57 | * Use the pcibios_fixups table or suffer the consequences. | ||
58 | */ | ||
59 | } | ||
60 | |||
61 | void __init pcibios_fixup_irqs(void) | ||
62 | { | ||
63 | struct pci_dev *dev = 0; | ||
64 | |||
65 | for_each_pci_dev(dev) { | ||
66 | /* | ||
67 | * The interrupt routing semantics here are quite trivial. | ||
68 | * | ||
69 | * We basically only support one interrupt, so we only bother | ||
70 | * updating a device's interrupt line with this single shared | ||
71 | * interrupt. Keeps routing quite simple, doesn't it? | ||
72 | */ | ||
73 | printk(KERN_NOTICE "PCI: Fixing up IRQ routing for device %s\n", | ||
74 | pci_name(dev)); | ||
75 | |||
76 | dev->irq = GAPSPCI_IRQ; | ||
77 | |||
78 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | ||
79 | } | ||
80 | } | ||
81 | |||
diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c new file mode 100644 index 000000000000..0c590fc7a081 --- /dev/null +++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/pci/fixups-rts7751r2d.c | ||
3 | * | ||
4 | * RTS7751R2D PCI fixups | ||
5 | * | ||
6 | * Copyright (C) 2003 Lineo uSolutions, Inc. | ||
7 | * Copyright (C) 2004 Paul Mundt | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | #include "pci-sh7751.h" | ||
14 | #include <asm/io.h> | ||
15 | |||
16 | #define PCIMCR_MRSET_OFF 0xBFFFFFFF | ||
17 | #define PCIMCR_RFSH_OFF 0xFFFFFFFB | ||
18 | |||
19 | int pci_fixup_pcic(void) | ||
20 | { | ||
21 | unsigned long bcr1, mcr; | ||
22 | |||
23 | bcr1 = inl(SH7751_BCR1); | ||
24 | bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ | ||
25 | outl(bcr1, PCI_REG(SH7751_PCIBCR1)); | ||
26 | |||
27 | /* Enable all interrupts, so we known what to fix */ | ||
28 | outl(0x0000c3ff, PCI_REG(SH7751_PCIINTM)); | ||
29 | outl(0x0000380f, PCI_REG(SH7751_PCIAINTM)); | ||
30 | |||
31 | outl(0xfb900047, PCI_REG(SH7751_PCICONF1)); | ||
32 | outl(0xab000001, PCI_REG(SH7751_PCICONF4)); | ||
33 | |||
34 | mcr = inl(SH7751_MCR); | ||
35 | mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; | ||
36 | outl(mcr, PCI_REG(SH7751_PCIMCR)); | ||
37 | |||
38 | outl(0x0c000000, PCI_REG(SH7751_PCICONF5)); | ||
39 | outl(0xd0000000, PCI_REG(SH7751_PCICONF6)); | ||
40 | outl(0x0c000000, PCI_REG(SH7751_PCILAR0)); | ||
41 | outl(0x00000000, PCI_REG(SH7751_PCILAR1)); | ||
42 | return 0; | ||
43 | } | ||
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c new file mode 100644 index 000000000000..57ac26c2171f --- /dev/null +++ b/arch/sh/drivers/pci/fixups-sh03.c | |||
@@ -0,0 +1,61 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/init.h> | ||
3 | #include <linux/types.h> | ||
4 | #include <linux/pci.h> | ||
5 | |||
6 | /* | ||
7 | * IRQ functions | ||
8 | */ | ||
9 | |||
10 | int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev) | ||
11 | { | ||
12 | int irq; | ||
13 | |||
14 | if (dev->bus->number == 0) { | ||
15 | switch (slot) { | ||
16 | case 4: return 5; /* eth0 */ | ||
17 | case 8: return 5; /* eth1 */ | ||
18 | case 6: return 2; /* PCI bridge */ | ||
19 | default: | ||
20 | printk("PCI: Bad IRQ mapping request for slot %d\n", slot); | ||
21 | return 2; | ||
22 | } | ||
23 | } else { | ||
24 | switch (pin) { | ||
25 | case 0: irq = 2; break; | ||
26 | case 1: irq = 2; break; | ||
27 | case 2: irq = 2; break; | ||
28 | case 3: irq = 2; break; | ||
29 | case 4: irq = 2; break; | ||
30 | default: irq = -1; break; | ||
31 | } | ||
32 | } | ||
33 | return irq; | ||
34 | } | ||
35 | |||
36 | static u8 __init sh03_no_swizzle(struct pci_dev *dev, u8 *pin) | ||
37 | { | ||
38 | /* no swizzling */ | ||
39 | return PCI_SLOT(dev->devfn); | ||
40 | } | ||
41 | |||
42 | static int sh03_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
43 | { | ||
44 | int irq = -1; | ||
45 | |||
46 | /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ | ||
47 | irq = pcibios_map_platform_irq(slot, pin, dev); | ||
48 | if( irq < 0 ) { | ||
49 | pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); | ||
50 | return irq; | ||
51 | } | ||
52 | |||
53 | pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); | ||
54 | |||
55 | return irq; | ||
56 | } | ||
57 | |||
58 | void __init pcibios_fixup_irqs(void) | ||
59 | { | ||
60 | pci_fixup_irqs(sh03_no_swizzle, sh03_pci_lookup_irq); | ||
61 | } | ||
diff --git a/arch/sh/drivers/pci/ops-bigsur.c b/arch/sh/drivers/pci/ops-bigsur.c new file mode 100644 index 000000000000..9b43da67804b --- /dev/null +++ b/arch/sh/drivers/pci/ops-bigsur.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/pci-bigsur.c | ||
3 | * | ||
4 | * By Dustin McIntire (dustin@sensoria.com) (c)2001 | ||
5 | * | ||
6 | * Ported to new API by Paul Mundt <lethal@linux-sh.org>. | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | * | ||
11 | * PCI initialization for the Hitachi Big Sur Evaluation Board | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pci.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | #include "pci-sh7751.h" | ||
23 | #include <asm/bigsur/bigsur.h> | ||
24 | |||
25 | #define BIGSUR_PCI_IO 0x4000 | ||
26 | #define BIGSUR_PCI_MEM 0xfd000000 | ||
27 | |||
28 | static struct resource sh7751_io_resource = { | ||
29 | .name = "SH7751 IO", | ||
30 | .start = BIGSUR_PCI_IO, | ||
31 | .end = BIGSUR_PCI_IO + (64*1024) - 1, | ||
32 | .flags = IORESOURCE_IO, | ||
33 | }; | ||
34 | |||
35 | static struct resource sh7751_mem_resource = { | ||
36 | .name = "SH7751 mem", | ||
37 | .start = BIGSUR_PCI_MEM, | ||
38 | .end = BIGSUR_PCI_MEM + (64*1024*1024) - 1, | ||
39 | .flags = IORESOURCE_MEM, | ||
40 | }; | ||
41 | |||
42 | extern struct pci_ops sh7751_pci_ops; | ||
43 | |||
44 | struct pci_channel board_pci_channels[] = { | ||
45 | { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, | ||
46 | { 0, } | ||
47 | }; | ||
48 | |||
49 | static struct sh7751_pci_address_map sh7751_pci_map = { | ||
50 | .window0 = { | ||
51 | .base = SH7751_CS3_BASE_ADDR, | ||
52 | .size = BIGSUR_LSR0_SIZE, | ||
53 | }, | ||
54 | |||
55 | .window1 = { | ||
56 | .base = SH7751_CS3_BASE_ADDR, | ||
57 | .size = BIGSUR_LSR1_SIZE, | ||
58 | }, | ||
59 | }; | ||
60 | |||
61 | /* | ||
62 | * Initialize the Big Sur PCI interface | ||
63 | * Setup hardware to be Central Funtion | ||
64 | * Copy the BSR regs to the PCI interface | ||
65 | * Setup PCI windows into local RAM | ||
66 | */ | ||
67 | int __init pcibios_init_platform(void) | ||
68 | { | ||
69 | return sh7751_pcic_init(&sh7751_pci_map); | ||
70 | } | ||
71 | |||
72 | int pcibios_map_platform_irq(u8 slot, u8 pin) | ||
73 | { | ||
74 | /* | ||
75 | * The Big Sur can be used in a CPCI chassis, but the SH7751 PCI | ||
76 | * interface is on the wrong end of the board so that it can also | ||
77 | * support a V320 CPI interface chip... Therefor the IRQ mapping is | ||
78 | * somewhat use dependent... I'l assume a linear map for now, i.e. | ||
79 | * INTA=slot0,pin0... INTD=slot3,pin0... | ||
80 | */ | ||
81 | int irq = (slot + pin-1) % 4 + BIGSUR_SH7751_PCI_IRQ_BASE; | ||
82 | |||
83 | PCIDBG(2, "PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n", | ||
84 | slot, pin-1+'A', irq); | ||
85 | |||
86 | return irq; | ||
87 | } | ||
88 | |||
diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c new file mode 100644 index 000000000000..69af80b93e3f --- /dev/null +++ b/arch/sh/drivers/pci/ops-dreamcast.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * arch/sh/pci/ops-dreamcast.c | ||
3 | * | ||
4 | * PCI operations for the Sega Dreamcast | ||
5 | * | ||
6 | * Copyright (C) 2001, 2002 M. R. Brown | ||
7 | * Copyright (C) 2002, 2003 Paul Mundt | ||
8 | * | ||
9 | * This file originally bore the message (with enclosed-$): | ||
10 | * Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp | ||
11 | * Dreamcast PCI: Supports SEGA Broadband Adaptor only. | ||
12 | * | ||
13 | * This file is subject to the terms and conditions of the GNU General Public | ||
14 | * License. See the file "COPYING" in the main directory of this archive | ||
15 | * for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/param.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/irq.h> | ||
25 | #include <linux/pci.h> | ||
26 | |||
27 | #include <asm/io.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/mach/pci.h> | ||
30 | |||
31 | static struct resource gapspci_io_resource = { | ||
32 | .name = "GAPSPCI IO", | ||
33 | .start = GAPSPCI_BBA_CONFIG, | ||
34 | .end = GAPSPCI_BBA_CONFIG + GAPSPCI_BBA_CONFIG_SIZE - 1, | ||
35 | .flags = IORESOURCE_IO, | ||
36 | }; | ||
37 | |||
38 | static struct resource gapspci_mem_resource = { | ||
39 | .name = "GAPSPCI mem", | ||
40 | .start = GAPSPCI_DMA_BASE, | ||
41 | .end = GAPSPCI_DMA_BASE + GAPSPCI_DMA_SIZE - 1, | ||
42 | .flags = IORESOURCE_MEM, | ||
43 | }; | ||
44 | |||
45 | static struct pci_ops gapspci_pci_ops; | ||
46 | |||
47 | struct pci_channel board_pci_channels[] = { | ||
48 | { &gapspci_pci_ops, &gapspci_io_resource, | ||
49 | &gapspci_mem_resource, 0, 1 }, | ||
50 | { 0, } | ||
51 | }; | ||
52 | |||
53 | /* | ||
54 | * The !gapspci_config_access case really shouldn't happen, ever, unless | ||
55 | * someone implicitly messes around with the last devfn value.. otherwise we | ||
56 | * only support a single device anyways, and if we didn't have a BBA, we | ||
57 | * wouldn't make it terribly far through the PCI setup anyways. | ||
58 | * | ||
59 | * Also, we could very easily support both Type 0 and Type 1 configurations | ||
60 | * here, but since it doesn't seem that there is any such implementation in | ||
61 | * existance, we don't bother. | ||
62 | * | ||
63 | * I suppose if someone actually gets around to ripping the chip out of | ||
64 | * the BBA and hanging some more devices off of it, then this might be | ||
65 | * something to take into consideration. However, due to the cost of the BBA, | ||
66 | * and the general lack of activity by DC hardware hackers, this doesn't seem | ||
67 | * likely to happen anytime soon. | ||
68 | */ | ||
69 | static int gapspci_config_access(unsigned char bus, unsigned int devfn) | ||
70 | { | ||
71 | return (bus == 0) && (devfn == 0); | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * We can also actually read and write in b/w/l sizes! Thankfully this part | ||
76 | * was at least done right, and we don't have to do the stupid masking and | ||
77 | * shifting that we do on the 7751! Small wonders never cease to amaze. | ||
78 | */ | ||
79 | static int gapspci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) | ||
80 | { | ||
81 | *val = 0xffffffff; | ||
82 | |||
83 | if (!gapspci_config_access(bus->number, devfn)) | ||
84 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
85 | |||
86 | switch (size) { | ||
87 | case 1: *val = inb(GAPSPCI_BBA_CONFIG+where); break; | ||
88 | case 2: *val = inw(GAPSPCI_BBA_CONFIG+where); break; | ||
89 | case 4: *val = inl(GAPSPCI_BBA_CONFIG+where); break; | ||
90 | } | ||
91 | |||
92 | return PCIBIOS_SUCCESSFUL; | ||
93 | } | ||
94 | |||
95 | static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) | ||
96 | { | ||
97 | if (!gapspci_config_access(bus->number, devfn)) | ||
98 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
99 | |||
100 | switch (size) { | ||
101 | case 1: outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break; | ||
102 | case 2: outw((u16)val, GAPSPCI_BBA_CONFIG+where); break; | ||
103 | case 4: outl((u32)val, GAPSPCI_BBA_CONFIG+where); break; | ||
104 | } | ||
105 | |||
106 | return PCIBIOS_SUCCESSFUL; | ||
107 | } | ||
108 | |||
109 | static struct pci_ops gapspci_pci_ops = { | ||
110 | .read = gapspci_read, | ||
111 | .write = gapspci_write, | ||
112 | }; | ||
113 | |||
114 | /* | ||
115 | * gapspci init | ||
116 | */ | ||
117 | |||
118 | int __init gapspci_init(void) | ||
119 | { | ||
120 | char idbuf[16]; | ||
121 | int i; | ||
122 | |||
123 | /* | ||
124 | * FIXME: All of this wants documenting to some degree, | ||
125 | * even some basic register definitions would be nice. | ||
126 | * | ||
127 | * I haven't seen anything this ugly since.. maple. | ||
128 | */ | ||
129 | |||
130 | for (i=0; i<16; i++) | ||
131 | idbuf[i] = inb(GAPSPCI_REGS+i); | ||
132 | |||
133 | if (strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16)) | ||
134 | return -ENODEV; | ||
135 | |||
136 | outl(0x5a14a501, GAPSPCI_REGS+0x18); | ||
137 | |||
138 | for (i=0; i<1000000; i++) | ||
139 | ; | ||
140 | |||
141 | if (inl(GAPSPCI_REGS+0x18) != 1) | ||
142 | return -EINVAL; | ||
143 | |||
144 | outl(0x01000000, GAPSPCI_REGS+0x20); | ||
145 | outl(0x01000000, GAPSPCI_REGS+0x24); | ||
146 | |||
147 | outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28); | ||
148 | outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c); | ||
149 | |||
150 | outl(1, GAPSPCI_REGS+0x14); | ||
151 | outl(1, GAPSPCI_REGS+0x34); | ||
152 | |||
153 | /* Setting Broadband Adapter */ | ||
154 | outw(0xf900, GAPSPCI_BBA_CONFIG+0x06); | ||
155 | outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30); | ||
156 | outb(0x00, GAPSPCI_BBA_CONFIG+0x3c); | ||
157 | outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d); | ||
158 | outw(0x0006, GAPSPCI_BBA_CONFIG+0x04); | ||
159 | outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); | ||
160 | outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | /* Haven't done anything here as yet */ | ||
166 | char * __devinit pcibios_setup(char *str) | ||
167 | { | ||
168 | return str; | ||
169 | } | ||
diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c new file mode 100644 index 000000000000..beafa11f4d0c --- /dev/null +++ b/arch/sh/drivers/pci/ops-rts7751r2d.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/kernel/pci-rts7751r2d.c | ||
3 | * | ||
4 | * Author: Ian DaSilva (idasilva@mvista.com) | ||
5 | * | ||
6 | * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. | ||
7 | * | ||
8 | * May be copied or modified under the terms of the GNU General Public | ||
9 | * License. See linux/COPYING for more information. | ||
10 | * | ||
11 | * PCI initialization for the Renesas SH7751R RTS7751R2D board | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/module.h> | ||
21 | |||
22 | #include <asm/io.h> | ||
23 | #include "pci-sh7751.h" | ||
24 | #include <asm/rts7751r2d/rts7751r2d.h> | ||
25 | |||
26 | int __init pcibios_map_platform_irq(u8 slot, u8 pin) | ||
27 | { | ||
28 | switch (slot) { | ||
29 | case 0: return IRQ_PCISLOT1; /* PCI Extend slot #1 */ | ||
30 | case 1: return IRQ_PCISLOT2; /* PCI Extend slot #2 */ | ||
31 | case 2: return IRQ_PCMCIA; /* PCI Cardbus Bridge */ | ||
32 | case 3: return IRQ_PCIETH; /* Realtek Ethernet controller */ | ||
33 | default: | ||
34 | printk("PCI: Bad IRQ mapping request for slot %d\n", slot); | ||
35 | return -1; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | static struct resource sh7751_io_resource = { | ||
40 | .name = "SH7751_IO", | ||
41 | .start = 0x4000, | ||
42 | .end = 0x4000 + SH7751_PCI_IO_SIZE - 1, | ||
43 | .flags = IORESOURCE_IO | ||
44 | }; | ||
45 | |||
46 | static struct resource sh7751_mem_resource = { | ||
47 | .name = "SH7751_mem", | ||
48 | .start = SH7751_PCI_MEMORY_BASE, | ||
49 | .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, | ||
50 | .flags = IORESOURCE_MEM | ||
51 | }; | ||
52 | |||
53 | extern struct pci_ops sh7751_pci_ops; | ||
54 | |||
55 | struct pci_channel board_pci_channels[] = { | ||
56 | { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, | ||
57 | { NULL, NULL, NULL, 0, 0 }, | ||
58 | }; | ||
59 | EXPORT_SYMBOL(board_pci_channels); | ||
60 | |||
61 | static struct sh7751_pci_address_map sh7751_pci_map = { | ||
62 | .window0 = { | ||
63 | .base = SH7751_CS3_BASE_ADDR, | ||
64 | .size = 0x04000000, | ||
65 | }, | ||
66 | |||
67 | .window1 = { | ||
68 | .base = 0x00000000, /* Unused */ | ||
69 | .size = 0x00000000, /* Unused */ | ||
70 | }, | ||
71 | |||
72 | .flags = SH7751_PCIC_NO_RESET, | ||
73 | }; | ||
74 | |||
75 | int __init pcibios_init_platform(void) | ||
76 | { | ||
77 | return sh7751_pcic_init(&sh7751_pci_map); | ||
78 | } | ||
79 | |||
diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c new file mode 100644 index 000000000000..df2199732348 --- /dev/null +++ b/arch/sh/drivers/pci/ops-sh03.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * linux/arch/sh/drivers/pci/ops-sh03.c | ||
3 | * | ||
4 | * PCI initialization for the Interface CTP/PCI-SH03 board | ||
5 | */ | ||
6 | |||
7 | #include <linux/config.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/types.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/pci.h> | ||
13 | #include <asm/io.h> | ||
14 | #include "pci-sh7751.h" | ||
15 | |||
16 | /* | ||
17 | * Description: This function sets up and initializes the pcic, sets | ||
18 | * up the BARS, maps the DRAM into the address space etc, etc. | ||
19 | */ | ||
20 | int __init pcibios_init_platform(void) | ||
21 | { | ||
22 | return 1; | ||
23 | } | ||
24 | |||
25 | static struct resource sh7751_io_resource = { | ||
26 | .name = "SH03 IO", | ||
27 | .start = SH7751_PCI_IO_BASE, | ||
28 | .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1, | ||
29 | .flags = IORESOURCE_IO | ||
30 | }; | ||
31 | |||
32 | static struct resource sh7751_mem_resource = { | ||
33 | .name = "SH03 mem", | ||
34 | .start = SH7751_PCI_MEMORY_BASE, | ||
35 | .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1, | ||
36 | .flags = IORESOURCE_MEM | ||
37 | }; | ||
38 | |||
39 | extern struct pci_ops sh7751_pci_ops; | ||
40 | |||
41 | struct pci_channel board_pci_channels[] = { | ||
42 | { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, | ||
43 | { NULL, NULL, NULL, 0, 0 }, | ||
44 | }; | ||
45 | |||
diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c new file mode 100644 index 000000000000..6fdb9765c99a --- /dev/null +++ b/arch/sh/drivers/pci/ops-snapgear.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * arch/sh/drivers/pci/ops-snapgear.c | ||
3 | * | ||
4 | * Author: David McCullough <davidm@snapgear.com> | ||
5 | * | ||
6 | * Ported to new API by Paul Mundt <lethal@linux-sh.org> | ||
7 | * | ||
8 | * Highly leveraged from pci-bigsur.c, written by Dustin McIntire. | ||
9 | * | ||
10 | * May be copied or modified under the terms of the GNU General Public | ||
11 | * License. See linux/COPYING for more information. | ||
12 | * | ||
13 | * PCI initialization for the SnapGear boards | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/pci.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include "pci-sh7751.h" | ||
25 | |||
26 | #define SNAPGEAR_PCI_IO 0x4000 | ||
27 | #define SNAPGEAR_PCI_MEM 0xfd000000 | ||
28 | |||
29 | /* PCI: default LOCAL memory window sizes (seen from PCI bus) */ | ||
30 | #define SNAPGEAR_LSR0_SIZE (64*(1<<20)) //64MB | ||
31 | #define SNAPGEAR_LSR1_SIZE (64*(1<<20)) //64MB | ||
32 | |||
33 | static struct resource sh7751_io_resource = { | ||
34 | .name = "SH7751 IO", | ||
35 | .start = SNAPGEAR_PCI_IO, | ||
36 | .end = SNAPGEAR_PCI_IO + (64*1024) - 1, /* 64KiB I/O */ | ||
37 | .flags = IORESOURCE_IO, | ||
38 | }; | ||
39 | |||
40 | static struct resource sh7751_mem_resource = { | ||
41 | .name = "SH7751 mem", | ||
42 | .start = SNAPGEAR_PCI_MEM, | ||
43 | .end = SNAPGEAR_PCI_MEM + (64*1024*1024) - 1, /* 64MiB mem */ | ||
44 | .flags = IORESOURCE_MEM, | ||
45 | }; | ||
46 | |||
47 | extern struct pci_ops sh7751_pci_ops; | ||
48 | |||
49 | struct pci_channel board_pci_channels[] = { | ||
50 | { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff }, | ||
51 | { 0, } | ||
52 | }; | ||
53 | |||
54 | static struct sh7751_pci_address_map sh7751_pci_map = { | ||
55 | .window0 = { | ||
56 | .base = SH7751_CS2_BASE_ADDR, | ||
57 | .size = SNAPGEAR_LSR0_SIZE, | ||
58 | }, | ||
59 | |||
60 | .window1 = { | ||
61 | .base = SH7751_CS2_BASE_ADDR, | ||
62 | .size = SNAPGEAR_LSR1_SIZE, | ||
63 | }, | ||
64 | |||
65 | .flags = SH7751_PCIC_NO_RESET, | ||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * Initialize the SnapGear PCI interface | ||
70 | * Setup hardware to be Central Funtion | ||
71 | * Copy the BSR regs to the PCI interface | ||
72 | * Setup PCI windows into local RAM | ||
73 | */ | ||
74 | int __init pcibios_init_platform(void) | ||
75 | { | ||
76 | return sh7751_pcic_init(&sh7751_pci_map); | ||
77 | } | ||
78 | |||
79 | int __init pcibios_map_platform_irq(u8 slot, u8 pin) | ||
80 | { | ||
81 | int irq = -1; | ||
82 | |||
83 | switch (slot) { | ||
84 | case 8: /* the PCI bridge */ break; | ||
85 | case 11: irq = 8; break; /* USB */ | ||
86 | case 12: irq = 11; break; /* PCMCIA */ | ||
87 | case 13: irq = 5; break; /* eth0 */ | ||
88 | case 14: irq = 8; break; /* eth1 */ | ||
89 | case 15: irq = 11; break; /* safenet (unused) */ | ||
90 | } | ||
91 | |||
92 | printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n", | ||
93 | slot, pin - 1 + 'A', irq); | ||
94 | |||
95 | return irq; | ||
96 | } | ||
97 | |||
98 | void __init pcibios_fixup(void) | ||
99 | { | ||
100 | /* Nothing to fixup .. */ | ||
101 | } | ||
102 | |||
diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c new file mode 100644 index 000000000000..4cef4d1d8c84 --- /dev/null +++ b/arch/sh/drivers/pci/pci-auto.c | |||
@@ -0,0 +1,555 @@ | |||
1 | /* | ||
2 | * PCI autoconfiguration library | ||
3 | * | ||
4 | * Author: Matt Porter <mporter@mvista.com> | ||
5 | * | ||
6 | * Copyright 2000, 2001 MontaVista Software Inc. | ||
7 | * Copyright 2001 Bradley D. LaRonde <brad@ltc.com> | ||
8 | * Copyright 2003 Paul Mundt <lethal@linux-sh.org> | ||
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 | |||
16 | /* | ||
17 | * Modified for MIPS by Jun Sun, jsun@mvista.com | ||
18 | * | ||
19 | * . Simplify the interface between pci_auto and the rest: a single function. | ||
20 | * . Assign resources from low address to upper address. | ||
21 | * . change most int to u32. | ||
22 | * | ||
23 | * Further modified to include it as mips generic code, ppopov@mvista.com. | ||
24 | * | ||
25 | * 2001-10-26 Bradley D. LaRonde <brad@ltc.com> | ||
26 | * - Add a top_bus argument to the "early config" functions so that | ||
27 | * they can set a fake parent bus pointer to convince the underlying | ||
28 | * pci ops to use type 1 configuration for sub busses. | ||
29 | * - Set bridge base and limit registers correctly. | ||
30 | * - Align io and memory base properly before and after bridge setup. | ||
31 | * - Don't fall through to pci_setup_bars for bridge. | ||
32 | * - Reformat the debug output to look more like lspci's output. | ||
33 | * | ||
34 | * Cloned for SuperH by M. R. Brown, mrbrown@0xd6.org | ||
35 | * | ||
36 | * 2003-08-05 Paul Mundt <lethal@linux-sh.org> | ||
37 | * - Don't update the BAR values on systems that already have valid addresses | ||
38 | * and don't want these updated for whatever reason, by way of a new config | ||
39 | * option check. However, we still read in the old BAR values so that they | ||
40 | * can still be reported through the debug output. | ||
41 | */ | ||
42 | |||
43 | #include <linux/kernel.h> | ||
44 | #include <linux/init.h> | ||
45 | #include <linux/types.h> | ||
46 | #include <linux/pci.h> | ||
47 | |||
48 | #undef DEBUG | ||
49 | #ifdef DEBUG | ||
50 | #define DBG(x...) printk(x) | ||
51 | #else | ||
52 | #define DBG(x...) | ||
53 | #endif | ||
54 | |||
55 | /* | ||
56 | * These functions are used early on before PCI scanning is done | ||
57 | * and all of the pci_dev and pci_bus structures have been created. | ||
58 | */ | ||
59 | static struct pci_dev *fake_pci_dev(struct pci_channel *hose, | ||
60 | int top_bus, int busnr, int devfn) | ||
61 | { | ||
62 | static struct pci_dev dev; | ||
63 | static struct pci_bus bus; | ||
64 | |||
65 | dev.bus = &bus; | ||
66 | dev.sysdata = hose; | ||
67 | dev.devfn = devfn; | ||
68 | bus.number = busnr; | ||
69 | bus.ops = hose->pci_ops; | ||
70 | |||
71 | if(busnr != top_bus) | ||
72 | /* Fake a parent bus structure. */ | ||
73 | bus.parent = &bus; | ||
74 | else | ||
75 | bus.parent = NULL; | ||
76 | |||
77 | return &dev; | ||
78 | } | ||
79 | |||
80 | #define EARLY_PCI_OP(rw, size, type) \ | ||
81 | int early_##rw##_config_##size(struct pci_channel *hose, \ | ||
82 | int top_bus, int bus, int devfn, int offset, type value) \ | ||
83 | { \ | ||
84 | return pci_##rw##_config_##size( \ | ||
85 | fake_pci_dev(hose, top_bus, bus, devfn), \ | ||
86 | offset, value); \ | ||
87 | } | ||
88 | |||
89 | EARLY_PCI_OP(read, byte, u8 *) | ||
90 | EARLY_PCI_OP(read, word, u16 *) | ||
91 | EARLY_PCI_OP(read, dword, u32 *) | ||
92 | EARLY_PCI_OP(write, byte, u8) | ||
93 | EARLY_PCI_OP(write, word, u16) | ||
94 | EARLY_PCI_OP(write, dword, u32) | ||
95 | |||
96 | static struct resource *io_resource_inuse; | ||
97 | static struct resource *mem_resource_inuse; | ||
98 | |||
99 | static u32 pciauto_lower_iospc; | ||
100 | static u32 pciauto_upper_iospc; | ||
101 | |||
102 | static u32 pciauto_lower_memspc; | ||
103 | static u32 pciauto_upper_memspc; | ||
104 | |||
105 | static void __init | ||
106 | pciauto_setup_bars(struct pci_channel *hose, | ||
107 | int top_bus, | ||
108 | int current_bus, | ||
109 | int pci_devfn, | ||
110 | int bar_limit) | ||
111 | { | ||
112 | u32 bar_response, bar_size, bar_value; | ||
113 | u32 bar, addr_mask, bar_nr = 0; | ||
114 | u32 * upper_limit; | ||
115 | u32 * lower_limit; | ||
116 | int found_mem64 = 0; | ||
117 | |||
118 | for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) { | ||
119 | #if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) | ||
120 | u32 bar_addr; | ||
121 | |||
122 | /* Read the old BAR value */ | ||
123 | early_read_config_dword(hose, top_bus, | ||
124 | current_bus, | ||
125 | pci_devfn, | ||
126 | bar, | ||
127 | &bar_addr); | ||
128 | #endif | ||
129 | |||
130 | /* Tickle the BAR and get the response */ | ||
131 | early_write_config_dword(hose, top_bus, | ||
132 | current_bus, | ||
133 | pci_devfn, | ||
134 | bar, | ||
135 | 0xffffffff); | ||
136 | |||
137 | early_read_config_dword(hose, top_bus, | ||
138 | current_bus, | ||
139 | pci_devfn, | ||
140 | bar, | ||
141 | &bar_response); | ||
142 | |||
143 | #if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) | ||
144 | /* | ||
145 | * Write the old BAR value back out, only update the BAR | ||
146 | * if we implicitly want resources to be updated, which | ||
147 | * is done by the generic code further down. -- PFM. | ||
148 | */ | ||
149 | early_write_config_dword(hose, top_bus, | ||
150 | current_bus, | ||
151 | pci_devfn, | ||
152 | bar, | ||
153 | bar_addr); | ||
154 | #endif | ||
155 | |||
156 | /* If BAR is not implemented go to the next BAR */ | ||
157 | if (!bar_response) | ||
158 | continue; | ||
159 | |||
160 | /* | ||
161 | * Workaround for a BAR that doesn't use its upper word, | ||
162 | * like the ALi 1535D+ PCI DC-97 Controller Modem (M5457). | ||
163 | * bdl <brad@ltc.com> | ||
164 | */ | ||
165 | if (!(bar_response & 0xffff0000)) | ||
166 | bar_response |= 0xffff0000; | ||
167 | |||
168 | retry: | ||
169 | /* Check the BAR type and set our address mask */ | ||
170 | if (bar_response & PCI_BASE_ADDRESS_SPACE) { | ||
171 | addr_mask = PCI_BASE_ADDRESS_IO_MASK; | ||
172 | upper_limit = &pciauto_upper_iospc; | ||
173 | lower_limit = &pciauto_lower_iospc; | ||
174 | DBG(" I/O"); | ||
175 | } else { | ||
176 | if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == | ||
177 | PCI_BASE_ADDRESS_MEM_TYPE_64) | ||
178 | found_mem64 = 1; | ||
179 | |||
180 | addr_mask = PCI_BASE_ADDRESS_MEM_MASK; | ||
181 | upper_limit = &pciauto_upper_memspc; | ||
182 | lower_limit = &pciauto_lower_memspc; | ||
183 | DBG(" Mem"); | ||
184 | } | ||
185 | |||
186 | |||
187 | /* Calculate requested size */ | ||
188 | bar_size = ~(bar_response & addr_mask) + 1; | ||
189 | |||
190 | /* Allocate a base address */ | ||
191 | bar_value = ((*lower_limit - 1) & ~(bar_size - 1)) + bar_size; | ||
192 | |||
193 | if ((bar_value + bar_size) > *upper_limit) { | ||
194 | if (bar_response & PCI_BASE_ADDRESS_SPACE) { | ||
195 | if (io_resource_inuse->child) { | ||
196 | io_resource_inuse = | ||
197 | io_resource_inuse->child; | ||
198 | pciauto_lower_iospc = | ||
199 | io_resource_inuse->start; | ||
200 | pciauto_upper_iospc = | ||
201 | io_resource_inuse->end + 1; | ||
202 | goto retry; | ||
203 | } | ||
204 | |||
205 | } else { | ||
206 | if (mem_resource_inuse->child) { | ||
207 | mem_resource_inuse = | ||
208 | mem_resource_inuse->child; | ||
209 | pciauto_lower_memspc = | ||
210 | mem_resource_inuse->start; | ||
211 | pciauto_upper_memspc = | ||
212 | mem_resource_inuse->end + 1; | ||
213 | goto retry; | ||
214 | } | ||
215 | } | ||
216 | DBG(" unavailable -- skipping, value %x size %x\n", | ||
217 | bar_value, bar_size); | ||
218 | continue; | ||
219 | } | ||
220 | |||
221 | #ifdef CONFIG_PCI_AUTO_UPDATE_RESOURCES | ||
222 | /* Write it out and update our limit */ | ||
223 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
224 | bar, bar_value); | ||
225 | #endif | ||
226 | |||
227 | *lower_limit = bar_value + bar_size; | ||
228 | |||
229 | /* | ||
230 | * If we are a 64-bit decoder then increment to the | ||
231 | * upper 32 bits of the bar and force it to locate | ||
232 | * in the lower 4GB of memory. | ||
233 | */ | ||
234 | if (found_mem64) { | ||
235 | bar += 4; | ||
236 | early_write_config_dword(hose, top_bus, | ||
237 | current_bus, | ||
238 | pci_devfn, | ||
239 | bar, | ||
240 | 0x00000000); | ||
241 | } | ||
242 | |||
243 | DBG(" at 0x%.8x [size=0x%x]\n", bar_value, bar_size); | ||
244 | |||
245 | bar_nr++; | ||
246 | } | ||
247 | |||
248 | } | ||
249 | |||
250 | static void __init | ||
251 | pciauto_prescan_setup_bridge(struct pci_channel *hose, | ||
252 | int top_bus, | ||
253 | int current_bus, | ||
254 | int pci_devfn, | ||
255 | int sub_bus) | ||
256 | { | ||
257 | /* Configure bus number registers */ | ||
258 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
259 | PCI_PRIMARY_BUS, current_bus); | ||
260 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
261 | PCI_SECONDARY_BUS, sub_bus + 1); | ||
262 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
263 | PCI_SUBORDINATE_BUS, 0xff); | ||
264 | |||
265 | /* Align memory and I/O to 1MB and 4KB boundaries. */ | ||
266 | pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) | ||
267 | & ~(0x100000 - 1); | ||
268 | pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) | ||
269 | & ~(0x1000 - 1); | ||
270 | |||
271 | /* Set base (lower limit) of address range behind bridge. */ | ||
272 | early_write_config_word(hose, top_bus, current_bus, pci_devfn, | ||
273 | PCI_MEMORY_BASE, pciauto_lower_memspc >> 16); | ||
274 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
275 | PCI_IO_BASE, (pciauto_lower_iospc & 0x0000f000) >> 8); | ||
276 | early_write_config_word(hose, top_bus, current_bus, pci_devfn, | ||
277 | PCI_IO_BASE_UPPER16, pciauto_lower_iospc >> 16); | ||
278 | |||
279 | /* We don't support prefetchable memory for now, so disable */ | ||
280 | early_write_config_word(hose, top_bus, current_bus, pci_devfn, | ||
281 | PCI_PREF_MEMORY_BASE, 0); | ||
282 | early_write_config_word(hose, top_bus, current_bus, pci_devfn, | ||
283 | PCI_PREF_MEMORY_LIMIT, 0); | ||
284 | } | ||
285 | |||
286 | static void __init | ||
287 | pciauto_postscan_setup_bridge(struct pci_channel *hose, | ||
288 | int top_bus, | ||
289 | int current_bus, | ||
290 | int pci_devfn, | ||
291 | int sub_bus) | ||
292 | { | ||
293 | u32 temp; | ||
294 | |||
295 | /* | ||
296 | * [jsun] we always bump up baselines a little, so that if there | ||
297 | * nothing behind P2P bridge, we don't wind up overlapping IO/MEM | ||
298 | * spaces. | ||
299 | */ | ||
300 | pciauto_lower_memspc += 1; | ||
301 | pciauto_lower_iospc += 1; | ||
302 | |||
303 | /* Configure bus number registers */ | ||
304 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
305 | PCI_SUBORDINATE_BUS, sub_bus); | ||
306 | |||
307 | /* Set upper limit of address range behind bridge. */ | ||
308 | early_write_config_word(hose, top_bus, current_bus, pci_devfn, | ||
309 | PCI_MEMORY_LIMIT, pciauto_lower_memspc >> 16); | ||
310 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
311 | PCI_IO_LIMIT, (pciauto_lower_iospc & 0x0000f000) >> 8); | ||
312 | early_write_config_word(hose, top_bus, current_bus, pci_devfn, | ||
313 | PCI_IO_LIMIT_UPPER16, pciauto_lower_iospc >> 16); | ||
314 | |||
315 | /* Align memory and I/O to 1MB and 4KB boundaries. */ | ||
316 | pciauto_lower_memspc = (pciauto_lower_memspc + (0x100000 - 1)) | ||
317 | & ~(0x100000 - 1); | ||
318 | pciauto_lower_iospc = (pciauto_lower_iospc + (0x1000 - 1)) | ||
319 | & ~(0x1000 - 1); | ||
320 | |||
321 | /* Enable memory and I/O accesses, enable bus master */ | ||
322 | early_read_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
323 | PCI_COMMAND, &temp); | ||
324 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
325 | PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | ||
326 | | PCI_COMMAND_MASTER); | ||
327 | } | ||
328 | |||
329 | static void __init | ||
330 | pciauto_prescan_setup_cardbus_bridge(struct pci_channel *hose, | ||
331 | int top_bus, | ||
332 | int current_bus, | ||
333 | int pci_devfn, | ||
334 | int sub_bus) | ||
335 | { | ||
336 | /* Configure bus number registers */ | ||
337 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
338 | PCI_PRIMARY_BUS, current_bus); | ||
339 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
340 | PCI_SECONDARY_BUS, sub_bus + 1); | ||
341 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
342 | PCI_SUBORDINATE_BUS, 0xff); | ||
343 | |||
344 | /* Align memory and I/O to 4KB and 4 byte boundaries. */ | ||
345 | pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) | ||
346 | & ~(0x1000 - 1); | ||
347 | pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) | ||
348 | & ~(0x4 - 1); | ||
349 | |||
350 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
351 | PCI_CB_MEMORY_BASE_0, pciauto_lower_memspc); | ||
352 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
353 | PCI_CB_IO_BASE_0, pciauto_lower_iospc); | ||
354 | } | ||
355 | |||
356 | static void __init | ||
357 | pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose, | ||
358 | int top_bus, | ||
359 | int current_bus, | ||
360 | int pci_devfn, | ||
361 | int sub_bus) | ||
362 | { | ||
363 | u32 temp; | ||
364 | |||
365 | #if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) | ||
366 | /* | ||
367 | * [jsun] we always bump up baselines a little, so that if there | ||
368 | * nothing behind P2P bridge, we don't wind up overlapping IO/MEM | ||
369 | * spaces. | ||
370 | */ | ||
371 | pciauto_lower_memspc += 1; | ||
372 | pciauto_lower_iospc += 1; | ||
373 | #endif | ||
374 | |||
375 | /* | ||
376 | * Configure subordinate bus number. The PCI subsystem | ||
377 | * bus scan will renumber buses (reserving three additional | ||
378 | * for this PCI<->CardBus bridge for the case where a CardBus | ||
379 | * adapter contains a P2P or CB2CB bridge. | ||
380 | */ | ||
381 | |||
382 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
383 | PCI_SUBORDINATE_BUS, sub_bus); | ||
384 | |||
385 | /* | ||
386 | * Reserve an additional 4MB for mem space and 16KB for | ||
387 | * I/O space. This should cover any additional space | ||
388 | * requirement of unusual CardBus devices with | ||
389 | * additional bridges that can consume more address space. | ||
390 | * | ||
391 | * Although pcmcia-cs currently will reprogram bridge | ||
392 | * windows, the goal is to add an option to leave them | ||
393 | * alone and use the bridge window ranges as the regions | ||
394 | * that are searched for free resources upon hot-insertion | ||
395 | * of a device. This will allow a PCI<->CardBus bridge | ||
396 | * configured by this routine to happily live behind a | ||
397 | * P2P bridge in a system. | ||
398 | */ | ||
399 | #if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) | ||
400 | pciauto_lower_memspc += 0x00400000; | ||
401 | pciauto_lower_iospc += 0x00004000; | ||
402 | #endif | ||
403 | |||
404 | /* Align memory and I/O to 4KB and 4 byte boundaries. */ | ||
405 | pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1)) | ||
406 | & ~(0x1000 - 1); | ||
407 | pciauto_lower_iospc = (pciauto_lower_iospc + (0x4 - 1)) | ||
408 | & ~(0x4 - 1); | ||
409 | /* Set up memory and I/O filter limits, assume 32-bit I/O space */ | ||
410 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
411 | PCI_CB_MEMORY_LIMIT_0, pciauto_lower_memspc - 1); | ||
412 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
413 | PCI_CB_IO_LIMIT_0, pciauto_lower_iospc - 1); | ||
414 | |||
415 | /* Enable memory and I/O accesses, enable bus master */ | ||
416 | early_read_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
417 | PCI_COMMAND, &temp); | ||
418 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
419 | PCI_COMMAND, temp | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | | ||
420 | PCI_COMMAND_MASTER); | ||
421 | } | ||
422 | |||
423 | #define PCIAUTO_IDE_MODE_MASK 0x05 | ||
424 | |||
425 | static int __init | ||
426 | pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus) | ||
427 | { | ||
428 | int sub_bus; | ||
429 | u32 pci_devfn, pci_class, cmdstat, found_multi=0; | ||
430 | unsigned short vid, did; | ||
431 | unsigned char header_type; | ||
432 | int devfn_start = 0; | ||
433 | int devfn_stop = 0xff; | ||
434 | |||
435 | sub_bus = current_bus; | ||
436 | |||
437 | if (hose->first_devfn) | ||
438 | devfn_start = hose->first_devfn; | ||
439 | if (hose->last_devfn) | ||
440 | devfn_stop = hose->last_devfn; | ||
441 | |||
442 | for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) { | ||
443 | |||
444 | if (PCI_FUNC(pci_devfn) && !found_multi) | ||
445 | continue; | ||
446 | |||
447 | early_read_config_word(hose, top_bus, current_bus, pci_devfn, | ||
448 | PCI_VENDOR_ID, &vid); | ||
449 | |||
450 | if (vid == 0xffff) continue; | ||
451 | |||
452 | early_read_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
453 | PCI_HEADER_TYPE, &header_type); | ||
454 | |||
455 | if (!PCI_FUNC(pci_devfn)) | ||
456 | found_multi = header_type & 0x80; | ||
457 | |||
458 | early_read_config_word(hose, top_bus, current_bus, pci_devfn, | ||
459 | PCI_DEVICE_ID, &did); | ||
460 | |||
461 | early_read_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
462 | PCI_CLASS_REVISION, &pci_class); | ||
463 | |||
464 | DBG("%.2x:%.2x.%x Class %.4x: %.4x:%.4x", | ||
465 | current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn), | ||
466 | pci_class >> 16, vid, did); | ||
467 | if (pci_class & 0xff) | ||
468 | DBG(" (rev %.2x)", pci_class & 0xff); | ||
469 | DBG("\n"); | ||
470 | |||
471 | if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) { | ||
472 | DBG(" Bridge: primary=%.2x, secondary=%.2x\n", | ||
473 | current_bus, sub_bus + 1); | ||
474 | #if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D) | ||
475 | pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1); | ||
476 | #endif | ||
477 | pciauto_prescan_setup_bridge(hose, top_bus, current_bus, | ||
478 | pci_devfn, sub_bus); | ||
479 | DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", | ||
480 | sub_bus + 1, | ||
481 | pciauto_lower_iospc, pciauto_lower_memspc); | ||
482 | sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); | ||
483 | DBG("Back to bus %.2x\n", current_bus); | ||
484 | pciauto_postscan_setup_bridge(hose, top_bus, current_bus, | ||
485 | pci_devfn, sub_bus); | ||
486 | continue; | ||
487 | } else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) { | ||
488 | DBG(" CARDBUS Bridge: primary=%.2x, secondary=%.2x\n", | ||
489 | current_bus, sub_bus + 1); | ||
490 | DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn)); | ||
491 | /* Place CardBus Socket/ExCA registers */ | ||
492 | pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0); | ||
493 | |||
494 | pciauto_prescan_setup_cardbus_bridge(hose, top_bus, | ||
495 | current_bus, pci_devfn, sub_bus); | ||
496 | |||
497 | DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n", | ||
498 | sub_bus + 1, | ||
499 | pciauto_lower_iospc, pciauto_lower_memspc); | ||
500 | sub_bus = pciauto_bus_scan(hose, top_bus, sub_bus+1); | ||
501 | DBG("Back to bus %.2x, sub_bus is %x\n", current_bus, sub_bus); | ||
502 | pciauto_postscan_setup_cardbus_bridge(hose, top_bus, | ||
503 | current_bus, pci_devfn, sub_bus); | ||
504 | continue; | ||
505 | } else if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) { | ||
506 | |||
507 | unsigned char prg_iface; | ||
508 | |||
509 | early_read_config_byte(hose, top_bus, current_bus, | ||
510 | pci_devfn, PCI_CLASS_PROG, &prg_iface); | ||
511 | if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { | ||
512 | DBG("Skipping legacy mode IDE controller\n"); | ||
513 | continue; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * Found a peripheral, enable some standard | ||
519 | * settings | ||
520 | */ | ||
521 | early_read_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
522 | PCI_COMMAND, &cmdstat); | ||
523 | early_write_config_dword(hose, top_bus, current_bus, pci_devfn, | ||
524 | PCI_COMMAND, cmdstat | PCI_COMMAND_IO | | ||
525 | PCI_COMMAND_MEMORY | | ||
526 | PCI_COMMAND_MASTER); | ||
527 | #if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D) | ||
528 | early_write_config_byte(hose, top_bus, current_bus, pci_devfn, | ||
529 | PCI_LATENCY_TIMER, 0x80); | ||
530 | #endif | ||
531 | |||
532 | /* Allocate PCI I/O and/or memory space */ | ||
533 | pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_5); | ||
534 | } | ||
535 | return sub_bus; | ||
536 | } | ||
537 | |||
538 | int __init | ||
539 | pciauto_assign_resources(int busno, struct pci_channel *hose) | ||
540 | { | ||
541 | /* setup resource limits */ | ||
542 | io_resource_inuse = hose->io_resource; | ||
543 | mem_resource_inuse = hose->mem_resource; | ||
544 | |||
545 | pciauto_lower_iospc = io_resource_inuse->start; | ||
546 | pciauto_upper_iospc = io_resource_inuse->end + 1; | ||
547 | pciauto_lower_memspc = mem_resource_inuse->start; | ||
548 | pciauto_upper_memspc = mem_resource_inuse->end + 1; | ||
549 | DBG("Autoconfig PCI channel 0x%p\n", hose); | ||
550 | DBG("Scanning bus %.2x, I/O 0x%.8x:0x%.8x, Mem 0x%.8x:0x%.8x\n", | ||
551 | busno, pciauto_lower_iospc, pciauto_upper_iospc, | ||
552 | pciauto_lower_memspc, pciauto_upper_memspc); | ||
553 | |||
554 | return pciauto_bus_scan(hose, busno, busno); | ||
555 | } | ||
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c new file mode 100644 index 000000000000..30b14ac7ae5a --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh7751.c | |||
@@ -0,0 +1,417 @@ | |||
1 | /* | ||
2 | * Low-Level PCI Support for the SH7751 | ||
3 | * | ||
4 | * Dustin McIntire (dustin@sensoria.com) | ||
5 | * Derived from arch/i386/kernel/pci-*.c which bore the message: | ||
6 | * (c) 1999--2000 Martin Mares <mj@ucw.cz> | ||
7 | * | ||
8 | * Ported to the new API by Paul Mundt <lethal@linux-sh.org> | ||
9 | * With cleanup by Paul van Gool <pvangool@mimotech.com> | ||
10 | * | ||
11 | * May be copied or modified under the terms of the GNU General Public | ||
12 | * License. See linux/COPYING for more information. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #undef DEBUG | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/ioport.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include <asm/machvec.h> | ||
30 | #include <asm/io.h> | ||
31 | #include "pci-sh7751.h" | ||
32 | |||
33 | static unsigned int pci_probe = PCI_PROBE_CONF1; | ||
34 | extern int pci_fixup_pcic(void); | ||
35 | |||
36 | void pcibios_fixup_irqs(void) __attribute__ ((weak)); | ||
37 | |||
38 | /* | ||
39 | * Direct access to PCI hardware... | ||
40 | */ | ||
41 | |||
42 | #define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | ||
43 | |||
44 | /* | ||
45 | * Functions for accessing PCI configuration space with type 1 accesses | ||
46 | */ | ||
47 | static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn, | ||
48 | int where, int size, u32 *val) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | u32 data; | ||
52 | |||
53 | /* | ||
54 | * PCIPDR may only be accessed as 32 bit words, | ||
55 | * so we must do byte alignment by hand | ||
56 | */ | ||
57 | local_irq_save(flags); | ||
58 | outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); | ||
59 | data = inl(PCI_REG(SH7751_PCIPDR)); | ||
60 | local_irq_restore(flags); | ||
61 | |||
62 | switch (size) { | ||
63 | case 1: | ||
64 | *val = (data >> ((where & 3) << 3)) & 0xff; | ||
65 | break; | ||
66 | case 2: | ||
67 | *val = (data >> ((where & 2) << 3)) & 0xffff; | ||
68 | break; | ||
69 | case 4: | ||
70 | *val = data; | ||
71 | break; | ||
72 | default: | ||
73 | return PCIBIOS_FUNC_NOT_SUPPORTED; | ||
74 | } | ||
75 | |||
76 | return PCIBIOS_SUCCESSFUL; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Since SH7751 only does 32bit access we'll have to do a read, | ||
81 | * mask,write operation. | ||
82 | * We'll allow an odd byte offset, though it should be illegal. | ||
83 | */ | ||
84 | static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn, | ||
85 | int where, int size, u32 val) | ||
86 | { | ||
87 | unsigned long flags; | ||
88 | int shift; | ||
89 | u32 data; | ||
90 | |||
91 | local_irq_save(flags); | ||
92 | outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR)); | ||
93 | data = inl(PCI_REG(SH7751_PCIPDR)); | ||
94 | local_irq_restore(flags); | ||
95 | |||
96 | switch (size) { | ||
97 | case 1: | ||
98 | shift = (where & 3) << 3; | ||
99 | data &= ~(0xff << shift); | ||
100 | data |= ((val & 0xff) << shift); | ||
101 | break; | ||
102 | case 2: | ||
103 | shift = (where & 2) << 3; | ||
104 | data &= ~(0xffff << shift); | ||
105 | data |= ((val & 0xffff) << shift); | ||
106 | break; | ||
107 | case 4: | ||
108 | data = val; | ||
109 | break; | ||
110 | default: | ||
111 | return PCIBIOS_FUNC_NOT_SUPPORTED; | ||
112 | } | ||
113 | |||
114 | outl(data, PCI_REG(SH7751_PCIPDR)); | ||
115 | |||
116 | return PCIBIOS_SUCCESSFUL; | ||
117 | } | ||
118 | |||
119 | #undef CONFIG_CMD | ||
120 | |||
121 | struct pci_ops sh7751_pci_ops = { | ||
122 | .read = sh7751_pci_read, | ||
123 | .write = sh7751_pci_write, | ||
124 | }; | ||
125 | |||
126 | static int __init pci_check_direct(void) | ||
127 | { | ||
128 | unsigned int tmp, id; | ||
129 | |||
130 | /* check for SH7751/SH7751R hardware */ | ||
131 | id = inl(SH7751_PCIREG_BASE+SH7751_PCICONF0); | ||
132 | if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) && | ||
133 | id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) { | ||
134 | pr_debug("PCI: This is not an SH7751(R) (%x)\n", id); | ||
135 | return -ENODEV; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Check if configuration works. | ||
140 | */ | ||
141 | if (pci_probe & PCI_PROBE_CONF1) { | ||
142 | tmp = inl (PCI_REG(SH7751_PCIPAR)); | ||
143 | outl (0x80000000, PCI_REG(SH7751_PCIPAR)); | ||
144 | if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) { | ||
145 | outl (tmp, PCI_REG(SH7751_PCIPAR)); | ||
146 | printk(KERN_INFO "PCI: Using configuration type 1\n"); | ||
147 | request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1"); | ||
148 | return 0; | ||
149 | } | ||
150 | outl (tmp, PCI_REG(SH7751_PCIPAR)); | ||
151 | } | ||
152 | |||
153 | pr_debug("PCI: pci_check_direct failed\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | /***************************************************************************************/ | ||
158 | |||
159 | /* | ||
160 | * Handle bus scanning and fixups .... | ||
161 | */ | ||
162 | |||
163 | static void __init pci_fixup_ide_bases(struct pci_dev *d) | ||
164 | { | ||
165 | int i; | ||
166 | |||
167 | /* | ||
168 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | ||
169 | */ | ||
170 | if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) | ||
171 | return; | ||
172 | pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d)); | ||
173 | for(i=0; i<4; i++) { | ||
174 | struct resource *r = &d->resource[i]; | ||
175 | if ((r->start & ~0x80) == 0x374) { | ||
176 | r->start |= 2; | ||
177 | r->end = r->start; | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); | ||
183 | |||
184 | /* | ||
185 | * Called after each bus is probed, but before its children | ||
186 | * are examined. | ||
187 | */ | ||
188 | |||
189 | void __init pcibios_fixup_bus(struct pci_bus *b) | ||
190 | { | ||
191 | pci_read_bridge_bases(b); | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Initialization. Try all known PCI access methods. Note that we support | ||
196 | * using both PCI BIOS and direct access: in such cases, we use I/O ports | ||
197 | * to access config space. | ||
198 | * | ||
199 | * Note that the platform specific initialization (BSC registers, and memory | ||
200 | * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it | ||
201 | * exitst and via the platform defined function pcibios_init_platform(). | ||
202 | * See pci_bigsur.c for implementation; | ||
203 | * | ||
204 | * The BIOS version of the pci functions is not yet implemented but it is left | ||
205 | * in for completeness. Currently an error will be genereated at compile time. | ||
206 | */ | ||
207 | |||
208 | static int __init sh7751_pci_init(void) | ||
209 | { | ||
210 | int ret; | ||
211 | |||
212 | pr_debug("PCI: Starting intialization.\n"); | ||
213 | if ((ret = pci_check_direct()) != 0) | ||
214 | return ret; | ||
215 | |||
216 | return pcibios_init_platform(); | ||
217 | } | ||
218 | |||
219 | subsys_initcall(sh7751_pci_init); | ||
220 | |||
221 | static int __init __area_sdram_check(unsigned int area) | ||
222 | { | ||
223 | u32 word; | ||
224 | |||
225 | word = inl(SH7751_BCR1); | ||
226 | /* check BCR for SDRAM in area */ | ||
227 | if(((word >> area) & 1) == 0) { | ||
228 | printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n", | ||
229 | area, word); | ||
230 | return 0; | ||
231 | } | ||
232 | outl(word, PCI_REG(SH7751_PCIBCR1)); | ||
233 | |||
234 | word = (u16)inw(SH7751_BCR2); | ||
235 | /* check BCR2 for 32bit SDRAM interface*/ | ||
236 | if(((word >> (area << 1)) & 0x3) != 0x3) { | ||
237 | printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n", | ||
238 | area, word); | ||
239 | return 0; | ||
240 | } | ||
241 | outl(word, PCI_REG(SH7751_PCIBCR2)); | ||
242 | |||
243 | return 1; | ||
244 | } | ||
245 | |||
246 | int __init sh7751_pcic_init(struct sh7751_pci_address_map *map) | ||
247 | { | ||
248 | u32 reg; | ||
249 | u32 word; | ||
250 | |||
251 | /* Set the BCR's to enable PCI access */ | ||
252 | reg = inl(SH7751_BCR1); | ||
253 | reg |= 0x80000; | ||
254 | outl(reg, SH7751_BCR1); | ||
255 | |||
256 | /* Turn the clocks back on (not done in reset)*/ | ||
257 | outl(0, PCI_REG(SH7751_PCICLKR)); | ||
258 | /* Clear Powerdown IRQ's (not done in reset) */ | ||
259 | word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0; | ||
260 | outl(word, PCI_REG(SH7751_PCIPINT)); | ||
261 | |||
262 | /* | ||
263 | * This code is unused for some boards as it is done in the | ||
264 | * bootloader and doing it here means the MAC addresses loaded | ||
265 | * by the bootloader get lost. | ||
266 | */ | ||
267 | if (!(map->flags & SH7751_PCIC_NO_RESET)) { | ||
268 | /* toggle PCI reset pin */ | ||
269 | word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST; | ||
270 | outl(word,PCI_REG(SH7751_PCICR)); | ||
271 | /* Wait for a long time... not 1 sec. but long enough */ | ||
272 | mdelay(100); | ||
273 | word = SH7751_PCICR_PREFIX; | ||
274 | outl(word,PCI_REG(SH7751_PCICR)); | ||
275 | } | ||
276 | |||
277 | /* set the command/status bits to: | ||
278 | * Wait Cycle Control + Parity Enable + Bus Master + | ||
279 | * Mem space enable | ||
280 | */ | ||
281 | word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | | ||
282 | SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES; | ||
283 | outl(word, PCI_REG(SH7751_PCICONF1)); | ||
284 | |||
285 | /* define this host as the host bridge */ | ||
286 | word = SH7751_PCI_HOST_BRIDGE << 24; | ||
287 | outl(word, PCI_REG(SH7751_PCICONF2)); | ||
288 | |||
289 | /* Set IO and Mem windows to local address | ||
290 | * Make PCI and local address the same for easy 1 to 1 mapping | ||
291 | * Window0 = map->window0.size @ non-cached area base = SDRAM | ||
292 | * Window1 = map->window1.size @ cached area base = SDRAM | ||
293 | */ | ||
294 | word = map->window0.size - 1; | ||
295 | outl(word, PCI_REG(SH7751_PCILSR0)); | ||
296 | word = map->window1.size - 1; | ||
297 | outl(word, PCI_REG(SH7751_PCILSR1)); | ||
298 | /* Set the values on window 0 PCI config registers */ | ||
299 | word = P2SEGADDR(map->window0.base); | ||
300 | outl(word, PCI_REG(SH7751_PCILAR0)); | ||
301 | outl(word, PCI_REG(SH7751_PCICONF5)); | ||
302 | /* Set the values on window 1 PCI config registers */ | ||
303 | word = PHYSADDR(map->window1.base); | ||
304 | outl(word, PCI_REG(SH7751_PCILAR1)); | ||
305 | outl(word, PCI_REG(SH7751_PCICONF6)); | ||
306 | |||
307 | /* Set the local 16MB PCI memory space window to | ||
308 | * the lowest PCI mapped address | ||
309 | */ | ||
310 | word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK; | ||
311 | PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word); | ||
312 | outl(word , PCI_REG(SH7751_PCIMBR)); | ||
313 | |||
314 | /* Map IO space into PCI IO window | ||
315 | * The IO window is 64K-PCIBIOS_MIN_IO in size | ||
316 | * IO addresses will be translated to the | ||
317 | * PCI IO window base address | ||
318 | */ | ||
319 | PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO, | ||
320 | (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO); | ||
321 | |||
322 | /* | ||
323 | * XXX: For now, leave this board-specific. In the event we have other | ||
324 | * boards that need to do similar work, this can be wrapped. | ||
325 | */ | ||
326 | #ifdef CONFIG_SH_BIGSUR | ||
327 | bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0); | ||
328 | #endif | ||
329 | |||
330 | /* Make sure the MSB's of IO window are set to access PCI space correctly */ | ||
331 | word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK; | ||
332 | PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word); | ||
333 | outl(word, PCI_REG(SH7751_PCIIOBR)); | ||
334 | |||
335 | /* Set PCI WCRx, BCRx's, copy from BSC locations */ | ||
336 | |||
337 | /* check BCR for SDRAM in specified area */ | ||
338 | switch (map->window0.base) { | ||
339 | case SH7751_CS0_BASE_ADDR: word = __area_sdram_check(0); break; | ||
340 | case SH7751_CS1_BASE_ADDR: word = __area_sdram_check(1); break; | ||
341 | case SH7751_CS2_BASE_ADDR: word = __area_sdram_check(2); break; | ||
342 | case SH7751_CS3_BASE_ADDR: word = __area_sdram_check(3); break; | ||
343 | case SH7751_CS4_BASE_ADDR: word = __area_sdram_check(4); break; | ||
344 | case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break; | ||
345 | case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break; | ||
346 | } | ||
347 | |||
348 | if (!word) | ||
349 | return 0; | ||
350 | |||
351 | /* configure the wait control registers */ | ||
352 | word = inl(SH7751_WCR1); | ||
353 | outl(word, PCI_REG(SH7751_PCIWCR1)); | ||
354 | word = inl(SH7751_WCR2); | ||
355 | outl(word, PCI_REG(SH7751_PCIWCR2)); | ||
356 | word = inl(SH7751_WCR3); | ||
357 | outl(word, PCI_REG(SH7751_PCIWCR3)); | ||
358 | word = inl(SH7751_MCR); | ||
359 | outl(word, PCI_REG(SH7751_PCIMCR)); | ||
360 | |||
361 | /* NOTE: I'm ignoring the PCI error IRQs for now.. | ||
362 | * TODO: add support for the internal error interrupts and | ||
363 | * DMA interrupts... | ||
364 | */ | ||
365 | |||
366 | #ifdef CONFIG_SH_RTS7751R2D | ||
367 | pci_fixup_pcic(); | ||
368 | #endif | ||
369 | |||
370 | /* SH7751 init done, set central function init complete */ | ||
371 | /* use round robin mode to stop a device starving/overruning */ | ||
372 | word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM; | ||
373 | outl(word,PCI_REG(SH7751_PCICR)); | ||
374 | |||
375 | return 1; | ||
376 | } | ||
377 | |||
378 | char * __init pcibios_setup(char *str) | ||
379 | { | ||
380 | if (!strcmp(str, "off")) { | ||
381 | pci_probe = 0; | ||
382 | return NULL; | ||
383 | } | ||
384 | |||
385 | return str; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * IRQ functions | ||
390 | */ | ||
391 | static u8 __init sh7751_no_swizzle(struct pci_dev *dev, u8 *pin) | ||
392 | { | ||
393 | /* no swizzling */ | ||
394 | return PCI_SLOT(dev->devfn); | ||
395 | } | ||
396 | |||
397 | static int sh7751_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
398 | { | ||
399 | int irq = -1; | ||
400 | |||
401 | /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */ | ||
402 | irq = pcibios_map_platform_irq(slot,pin); | ||
403 | if( irq < 0 ) { | ||
404 | pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev)); | ||
405 | return irq; | ||
406 | } | ||
407 | |||
408 | pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq); | ||
409 | |||
410 | return irq; | ||
411 | } | ||
412 | |||
413 | void __init pcibios_fixup_irqs(void) | ||
414 | { | ||
415 | pci_fixup_irqs(sh7751_no_swizzle, sh7751_pci_lookup_irq); | ||
416 | } | ||
417 | |||
diff --git a/arch/sh/drivers/pci/pci-sh7751.h b/arch/sh/drivers/pci/pci-sh7751.h new file mode 100644 index 000000000000..1fee5cae10d1 --- /dev/null +++ b/arch/sh/drivers/pci/pci-sh7751.h | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * Low-Level PCI Support for SH7751 targets | ||
3 | * | ||
4 | * Dustin McIntire (dustin@sensoria.com) (c) 2001 | ||
5 | * Paul Mundt (lethal@linux-sh.org) (c) 2003 | ||
6 | * | ||
7 | * May be copied or modified under the terms of the GNU General Public | ||
8 | * License. See linux/COPYING for more information. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _PCI_SH7751_H_ | ||
13 | #define _PCI_SH7751_H_ | ||
14 | |||
15 | #include <linux/pci.h> | ||
16 | |||
17 | /* set debug level 4=verbose...1=terse */ | ||
18 | //#define DEBUG_PCI 3 | ||
19 | #undef DEBUG_PCI | ||
20 | |||
21 | #ifdef DEBUG_PCI | ||
22 | #define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); } | ||
23 | #else | ||
24 | #define PCIDBG(n, x...) | ||
25 | #endif | ||
26 | |||
27 | /* startup values */ | ||
28 | #define PCI_PROBE_BIOS 1 | ||
29 | #define PCI_PROBE_CONF1 2 | ||
30 | #define PCI_PROBE_CONF2 4 | ||
31 | #define PCI_NO_SORT 0x100 | ||
32 | #define PCI_BIOS_SORT 0x200 | ||
33 | #define PCI_NO_CHECKS 0x400 | ||
34 | #define PCI_ASSIGN_ROMS 0x1000 | ||
35 | #define PCI_BIOS_IRQ_SCAN 0x2000 | ||
36 | |||
37 | /* Platform Specific Values */ | ||
38 | #define SH7751_VENDOR_ID 0x1054 | ||
39 | #define SH7751_DEVICE_ID 0x3505 | ||
40 | #define SH7751R_DEVICE_ID 0x350e | ||
41 | |||
42 | /* SH7751 Specific Values */ | ||
43 | #define SH7751_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */ | ||
44 | #define SH7751_PCI_CONFIG_SIZE 0x1000000 /* Config space size */ | ||
45 | #define SH7751_PCI_MEMORY_BASE 0xFD000000 /* Memory space base addr */ | ||
46 | #define SH7751_PCI_MEM_SIZE 0x01000000 /* Size of Memory window */ | ||
47 | #define SH7751_PCI_IO_BASE 0xFE240000 /* IO space base address */ | ||
48 | #define SH7751_PCI_IO_SIZE 0x40000 /* Size of IO window */ | ||
49 | |||
50 | #define SH7751_PCIREG_BASE 0xFE200000 /* PCI regs base address */ | ||
51 | #define PCI_REG(n) (SH7751_PCIREG_BASE+ n) | ||
52 | |||
53 | #define SH7751_PCICONF0 0x0 /* PCI Config Reg 0 */ | ||
54 | #define SH7751_PCICONF0_DEVID 0xFFFF0000 /* Device ID */ | ||
55 | #define SH7751_PCICONF0_VNDID 0x0000FFFF /* Vendor ID */ | ||
56 | #define SH7751_PCICONF1 0x4 /* PCI Config Reg 1 */ | ||
57 | #define SH7751_PCICONF1_DPE 0x80000000 /* Data Parity Error */ | ||
58 | #define SH7751_PCICONF1_SSE 0x40000000 /* System Error Status */ | ||
59 | #define SH7751_PCICONF1_RMA 0x20000000 /* Master Abort */ | ||
60 | #define SH7751_PCICONF1_RTA 0x10000000 /* Target Abort Rx Status */ | ||
61 | #define SH7751_PCICONF1_STA 0x08000000 /* Target Abort Exec Status */ | ||
62 | #define SH7751_PCICONF1_DEV 0x06000000 /* Timing Status */ | ||
63 | #define SH7751_PCICONF1_DPD 0x01000000 /* Data Parity Status */ | ||
64 | #define SH7751_PCICONF1_FBBC 0x00800000 /* Back 2 Back Status */ | ||
65 | #define SH7751_PCICONF1_UDF 0x00400000 /* User Defined Status */ | ||
66 | #define SH7751_PCICONF1_66M 0x00200000 /* 66Mhz Operation Status */ | ||
67 | #define SH7751_PCICONF1_PM 0x00100000 /* Power Management Status */ | ||
68 | #define SH7751_PCICONF1_PBBE 0x00000200 /* Back 2 Back Control */ | ||
69 | #define SH7751_PCICONF1_SER 0x00000100 /* SERR Output Control */ | ||
70 | #define SH7751_PCICONF1_WCC 0x00000080 /* Wait Cycle Control */ | ||
71 | #define SH7751_PCICONF1_PER 0x00000040 /* Parity Error Response */ | ||
72 | #define SH7751_PCICONF1_VPS 0x00000020 /* VGA Pallet Snoop */ | ||
73 | #define SH7751_PCICONF1_MWIE 0x00000010 /* Memory Write+Invalidate */ | ||
74 | #define SH7751_PCICONF1_SPC 0x00000008 /* Special Cycle Control */ | ||
75 | #define SH7751_PCICONF1_BUM 0x00000004 /* Bus Master Control */ | ||
76 | #define SH7751_PCICONF1_MES 0x00000002 /* Memory Space Control */ | ||
77 | #define SH7751_PCICONF1_IOS 0x00000001 /* I/O Space Control */ | ||
78 | #define SH7751_PCICONF2 0x8 /* PCI Config Reg 2 */ | ||
79 | #define SH7751_PCICONF2_BCC 0xFF000000 /* Base Class Code */ | ||
80 | #define SH7751_PCICONF2_SCC 0x00FF0000 /* Sub-Class Code */ | ||
81 | #define SH7751_PCICONF2_RLPI 0x0000FF00 /* Programming Interface */ | ||
82 | #define SH7751_PCICONF2_REV 0x000000FF /* Revision ID */ | ||
83 | #define SH7751_PCICONF3 0xC /* PCI Config Reg 3 */ | ||
84 | #define SH7751_PCICONF3_BIST7 0x80000000 /* Bist Supported */ | ||
85 | #define SH7751_PCICONF3_BIST6 0x40000000 /* Bist Executing */ | ||
86 | #define SH7751_PCICONF3_BIST3_0 0x0F000000 /* Bist Passed */ | ||
87 | #define SH7751_PCICONF3_HD7 0x00800000 /* Single Funtion device */ | ||
88 | #define SH7751_PCICONF3_HD6_0 0x007F0000 /* Configuration Layout */ | ||
89 | #define SH7751_PCICONF3_LAT 0x0000FF00 /* Latency Timer */ | ||
90 | #define SH7751_PCICONF3_CLS 0x000000FF /* Cache Line Size */ | ||
91 | #define SH7751_PCICONF4 0x10 /* PCI Config Reg 4 */ | ||
92 | #define SH7751_PCICONF4_BASE 0xFFFFFFFC /* I/O Space Base Addr */ | ||
93 | #define SH7751_PCICONF4_ASI 0x00000001 /* Address Space Type */ | ||
94 | #define SH7751_PCICONF5 0x14 /* PCI Config Reg 5 */ | ||
95 | #define SH7751_PCICONF5_BASE 0xFFFFFFF0 /* Mem Space Base Addr */ | ||
96 | #define SH7751_PCICONF5_LAP 0x00000008 /* Prefetch Enabled */ | ||
97 | #define SH7751_PCICONF5_LAT 0x00000006 /* Local Memory type */ | ||
98 | #define SH7751_PCICONF5_ASI 0x00000001 /* Address Space Type */ | ||
99 | #define SH7751_PCICONF6 0x18 /* PCI Config Reg 6 */ | ||
100 | #define SH7751_PCICONF6_BASE 0xFFFFFFF0 /* Mem Space Base Addr */ | ||
101 | #define SH7751_PCICONF6_LAP 0x00000008 /* Prefetch Enabled */ | ||
102 | #define SH7751_PCICONF6_LAT 0x00000006 /* Local Memory type */ | ||
103 | #define SH7751_PCICONF6_ASI 0x00000001 /* Address Space Type */ | ||
104 | /* PCICONF7 - PCICONF10 are undefined */ | ||
105 | #define SH7751_PCICONF11 0x2C /* PCI Config Reg 11 */ | ||
106 | #define SH7751_PCICONF11_SSID 0xFFFF0000 /* Subsystem ID */ | ||
107 | #define SH7751_PCICONF11_SVID 0x0000FFFF /* Subsystem Vendor ID */ | ||
108 | /* PCICONF12 is undefined */ | ||
109 | #define SH7751_PCICONF13 0x34 /* PCI Config Reg 13 */ | ||
110 | #define SH7751_PCICONF13_CPTR 0x000000FF /* PM function pointer */ | ||
111 | /* PCICONF14 is undefined */ | ||
112 | #define SH7751_PCICONF15 0x3C /* PCI Config Reg 15 */ | ||
113 | #define SH7751_PCICONF15_IPIN 0x000000FF /* Interrupt Pin */ | ||
114 | #define SH7751_PCICONF16 0x40 /* PCI Config Reg 16 */ | ||
115 | #define SH7751_PCICONF16_PMES 0xF8000000 /* PME Support */ | ||
116 | #define SH7751_PCICONF16_D2S 0x04000000 /* D2 Support */ | ||
117 | #define SH7751_PCICONF16_D1S 0x02000000 /* D1 Support */ | ||
118 | #define SH7751_PCICONF16_DSI 0x00200000 /* Bit Device Init. */ | ||
119 | #define SH7751_PCICONF16_PMCK 0x00080000 /* Clock for PME req. */ | ||
120 | #define SH7751_PCICONF16_VER 0x00070000 /* PM Version */ | ||
121 | #define SH7751_PCICONF16_NIP 0x0000FF00 /* Next Item Pointer */ | ||
122 | #define SH7751_PCICONF16_CID 0x000000FF /* Capability Identifier */ | ||
123 | #define SH7751_PCICONF17 0x44 /* PCI Config Reg 17 */ | ||
124 | #define SH7751_PCICONF17_DATA 0xFF000000 /* Data field for PM */ | ||
125 | #define SH7751_PCICONF17_PMES 0x00800000 /* PME Status */ | ||
126 | #define SH7751_PCICONF17_DSCL 0x00600000 /* Data Scaling Value */ | ||
127 | #define SH7751_PCICONF17_DSEL 0x001E0000 /* Data Select */ | ||
128 | #define SH7751_PCICONF17_PMEN 0x00010000 /* PME Enable */ | ||
129 | #define SH7751_PCICONF17_PWST 0x00000003 /* Power State */ | ||
130 | /* SH7715 Internal PCI Registers */ | ||
131 | #define SH7751_PCICR 0x100 /* PCI Control Register */ | ||
132 | #define SH7751_PCICR_PREFIX 0xA5000000 /* CR prefix for write */ | ||
133 | #define SH7751_PCICR_TRSB 0x00000200 /* Target Read Single */ | ||
134 | #define SH7751_PCICR_BSWP 0x00000100 /* Target Byte Swap */ | ||
135 | #define SH7751_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */ | ||
136 | #define SH7751_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */ | ||
137 | #define SH7751_PCICR_MD 0x00000030 /* MD9 and MD10 status */ | ||
138 | #define SH7751_PCICR_SERR 0x00000008 /* SERR output assert */ | ||
139 | #define SH7751_PCICR_INTA 0x00000004 /* INTA output assert */ | ||
140 | #define SH7751_PCICR_PRST 0x00000002 /* PCI Reset Assert */ | ||
141 | #define SH7751_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */ | ||
142 | #define SH7751_PCILSR0 0x104 /* PCI Local Space Register0 */ | ||
143 | #define SH7751_PCILSR1 0x108 /* PCI Local Space Register1 */ | ||
144 | #define SH7751_PCILAR0 0x10C /* PCI Local Address Register1 */ | ||
145 | #define SH7751_PCILAR1 0x110 /* PCI Local Address Register1 */ | ||
146 | #define SH7751_PCIINT 0x114 /* PCI Interrupt Register */ | ||
147 | #define SH7751_PCIINT_MLCK 0x00008000 /* Master Lock Error */ | ||
148 | #define SH7751_PCIINT_TABT 0x00004000 /* Target Abort Error */ | ||
149 | #define SH7751_PCIINT_TRET 0x00000200 /* Target Retry Error */ | ||
150 | #define SH7751_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */ | ||
151 | #define SH7751_PCIINT_PRTY 0x00000080 /* Address Parity Error */ | ||
152 | #define SH7751_PCIINT_SERR 0x00000040 /* SERR Detection Error */ | ||
153 | #define SH7751_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */ | ||
154 | #define SH7751_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Error Det. */ | ||
155 | #define SH7751_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */ | ||
156 | #define SH7751_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */ | ||
157 | #define SH7751_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */ | ||
158 | #define SH7751_PCIINT_MRPD 0x00000002 /* Master Read PERR Detect */ | ||
159 | #define SH7751_PCIINTM 0x118 /* PCI Interrupt Mask Register */ | ||
160 | #define SH7751_PCIALR 0x11C /* Error Address Register */ | ||
161 | #define SH7751_PCICLR 0x120 /* Error Command/Data Register */ | ||
162 | #define SH7751_PCICLR_MPIO 0x80000000 /* Error Command/Data Register */ | ||
163 | #define SH7751_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */ | ||
164 | #define SH7751_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */ | ||
165 | #define SH7751_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */ | ||
166 | #define SH7751_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */ | ||
167 | #define SH7751_PCICLR_TGT 0x04000000 /* Target Transfer Error */ | ||
168 | #define SH7751_PCICLR_CMDL 0x0000000F /* PCI Command at Error */ | ||
169 | #define SH7751_PCIAINT 0x130 /* Arbiter Interrupt Register */ | ||
170 | #define SH7751_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */ | ||
171 | #define SH7751_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */ | ||
172 | #define SH7751_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */ | ||
173 | #define SH7751_PCIAINT_TABT 0x00000008 /* Target Abort */ | ||
174 | #define SH7751_PCIAINT_MABT 0x00000004 /* Master Abort */ | ||
175 | #define SH7751_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */ | ||
176 | #define SH7751_PCIAINT_WDPE 0x00000002 /* Write Data Parity Error */ | ||
177 | #define SH7751_PCIAINTM 0x134 /* Arbiter Int. Mask Register */ | ||
178 | #define SH7751_PCIBMLR 0x138 /* Error Bus Master Register */ | ||
179 | #define SH7751_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */ | ||
180 | #define SH7751_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */ | ||
181 | #define SH7751_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */ | ||
182 | #define SH7751_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */ | ||
183 | #define SH7751_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */ | ||
184 | #define SH7751_PCIDMABT 0x140 /* DMA Transfer Arb. Register */ | ||
185 | #define SH7751_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */ | ||
186 | #define SH7751_PCIDPA0 0x180 /* DMA0 Transfer Addr. Register */ | ||
187 | #define SH7751_PCIDLA0 0x184 /* DMA0 Local Addr. Register */ | ||
188 | #define SH7751_PCIDTC0 0x188 /* DMA0 Transfer Cnt. Register */ | ||
189 | #define SH7751_PCIDCR0 0x18C /* DMA0 Control Register */ | ||
190 | #define SH7751_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */ | ||
191 | #define SH7751_PCIDCR_MAST 0x00000100 /* DMA Termination Type */ | ||
192 | #define SH7751_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/ | ||
193 | #define SH7751_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */ | ||
194 | #define SH7751_PCIDCR_LHLD 0x00000020 /* Local Address Control */ | ||
195 | #define SH7751_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/ | ||
196 | #define SH7751_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */ | ||
197 | #define SH7751_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */ | ||
198 | #define SH7751_PCIDCR_STOP 0x00000002 /* Force DMA Stop */ | ||
199 | #define SH7751_PCIDCR_STRT 0x00000001 /* DMA Start */ | ||
200 | #define SH7751_PCIDPA1 0x190 /* DMA1 Transfer Addr. Register */ | ||
201 | #define SH7751_PCIDLA1 0x194 /* DMA1 Local Addr. Register */ | ||
202 | #define SH7751_PCIDTC1 0x198 /* DMA1 Transfer Cnt. Register */ | ||
203 | #define SH7751_PCIDCR1 0x19C /* DMA1 Control Register */ | ||
204 | #define SH7751_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. Register */ | ||
205 | #define SH7751_PCIDLA2 0x1A4 /* DMA2 Local Addr. Register */ | ||
206 | #define SH7751_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. Register */ | ||
207 | #define SH7751_PCIDCR2 0x1AC /* DMA2 Control Register */ | ||
208 | #define SH7751_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. Register */ | ||
209 | #define SH7751_PCIDLA3 0x1B4 /* DMA3 Local Addr. Register */ | ||
210 | #define SH7751_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. Register */ | ||
211 | #define SH7751_PCIDCR3 0x1BC /* DMA3 Control Register */ | ||
212 | #define SH7751_PCIPAR 0x1C0 /* PIO Address Register */ | ||
213 | #define SH7751_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */ | ||
214 | #define SH7751_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */ | ||
215 | #define SH7751_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */ | ||
216 | #define SH7751_PCIPAR_REGAD 0x000000FC /* Register Address Number */ | ||
217 | #define SH7751_PCIMBR 0x1C4 /* Memory Base Address Register */ | ||
218 | #define SH7751_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */ | ||
219 | #define SH7751_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */ | ||
220 | #define SH7751_PCIIOBR 0x1C8 /* I/O Base Address Register */ | ||
221 | #define SH7751_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */ | ||
222 | #define SH7751_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */ | ||
223 | #define SH7751_PCIPINT 0x1CC /* Power Mgmnt Int. Register */ | ||
224 | #define SH7751_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */ | ||
225 | #define SH7751_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */ | ||
226 | #define SH7751_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */ | ||
227 | #define SH7751_PCICLKR 0x1D4 /* Clock Ctrl. Register */ | ||
228 | #define SH7751_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */ | ||
229 | #define SH7751_PCICLKR_BCSTP 0x00000002 /* BCLK Clock Stop */ | ||
230 | /* For definitions of BCR, MCR see ... */ | ||
231 | #define SH7751_PCIBCR1 0x1E0 /* Memory BCR1 Register */ | ||
232 | #define SH7751_PCIBCR2 0x1E4 /* Memory BCR2 Register */ | ||
233 | #define SH7751_PCIWCR1 0x1E8 /* Wait Control 1 Register */ | ||
234 | #define SH7751_PCIWCR2 0x1EC /* Wait Control 2 Register */ | ||
235 | #define SH7751_PCIWCR3 0x1F0 /* Wait Control 3 Register */ | ||
236 | #define SH7751_PCIMCR 0x1F4 /* Memory Control Register */ | ||
237 | #define SH7751_PCIBCR3 0x1f8 /* Memory BCR3 Register */ | ||
238 | #define SH7751_PCIPCTR 0x200 /* Port Control Register */ | ||
239 | #define SH7751_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */ | ||
240 | #define SH7751_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */ | ||
241 | #define SH7751_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */ | ||
242 | #define SH7751_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */ | ||
243 | #define SH7751_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */ | ||
244 | #define SH7751_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */ | ||
245 | #define SH7751_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */ | ||
246 | #define SH7751_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */ | ||
247 | #define SH7751_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */ | ||
248 | #define SH7751_PCIPDTR 0x204 /* Port Data Register */ | ||
249 | #define SH7751_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */ | ||
250 | #define SH7751_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */ | ||
251 | #define SH7751_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */ | ||
252 | #define SH7751_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */ | ||
253 | #define SH7751_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */ | ||
254 | #define SH7751_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */ | ||
255 | #define SH7751_PCIPDR 0x220 /* Port IO Data Register */ | ||
256 | |||
257 | /* Memory Control Registers */ | ||
258 | #define SH7751_BCR1 0xFF800000 /* Memory BCR1 Register */ | ||
259 | #define SH7751_BCR2 0xFF800004 /* Memory BCR2 Register */ | ||
260 | #define SH7751_BCR3 0xFF800050 /* Memory BCR3 Register */ | ||
261 | #define SH7751_BCR4 0xFE0A00F0 /* Memory BCR4 Register */ | ||
262 | #define SH7751_WCR1 0xFF800008 /* Wait Control 1 Register */ | ||
263 | #define SH7751_WCR2 0xFF80000C /* Wait Control 2 Register */ | ||
264 | #define SH7751_WCR3 0xFF800010 /* Wait Control 3 Register */ | ||
265 | #define SH7751_MCR 0xFF800014 /* Memory Control Register */ | ||
266 | |||
267 | /* General Memory Config Addresses */ | ||
268 | #define SH7751_CS0_BASE_ADDR 0x0 | ||
269 | #define SH7751_MEM_REGION_SIZE 0x04000000 | ||
270 | #define SH7751_CS1_BASE_ADDR (SH7751_CS0_BASE_ADDR + SH7751_MEM_REGION_SIZE) | ||
271 | #define SH7751_CS2_BASE_ADDR (SH7751_CS1_BASE_ADDR + SH7751_MEM_REGION_SIZE) | ||
272 | #define SH7751_CS3_BASE_ADDR (SH7751_CS2_BASE_ADDR + SH7751_MEM_REGION_SIZE) | ||
273 | #define SH7751_CS4_BASE_ADDR (SH7751_CS3_BASE_ADDR + SH7751_MEM_REGION_SIZE) | ||
274 | #define SH7751_CS5_BASE_ADDR (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE) | ||
275 | #define SH7751_CS6_BASE_ADDR (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE) | ||
276 | |||
277 | /* General PCI values */ | ||
278 | #define SH7751_PCI_HOST_BRIDGE 0x6 | ||
279 | |||
280 | /* Flags */ | ||
281 | #define SH7751_PCIC_NO_RESET 0x0001 | ||
282 | |||
283 | /* External functions defined per platform i.e. Big Sur, SE... (these could be routed | ||
284 | * through the machine vectors... */ | ||
285 | extern int pcibios_init_platform(void); | ||
286 | extern int pcibios_map_platform_irq(u8 slot, u8 pin); | ||
287 | |||
288 | struct sh7751_pci_address_space { | ||
289 | unsigned long base; | ||
290 | unsigned long size; | ||
291 | }; | ||
292 | |||
293 | struct sh7751_pci_address_map { | ||
294 | struct sh7751_pci_address_space window0; | ||
295 | struct sh7751_pci_address_space window1; | ||
296 | unsigned long flags; | ||
297 | }; | ||
298 | |||
299 | /* arch/sh/drivers/pci/pci-sh7751.c */ | ||
300 | extern int sh7751_pcic_init(struct sh7751_pci_address_map *map); | ||
301 | |||
302 | #endif /* _PCI_SH7751_H_ */ | ||
303 | |||
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c new file mode 100644 index 000000000000..cb6752131156 --- /dev/null +++ b/arch/sh/drivers/pci/pci-st40.c | |||
@@ -0,0 +1,509 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Support functions for the ST40 PCI hardware. | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/smp.h> | ||
13 | #include <linux/smp_lock.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <asm/pci.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/interrupt.h> /* irqreturn_t */ | ||
22 | |||
23 | #include "pci-st40.h" | ||
24 | |||
25 | /* This is in P2 of course */ | ||
26 | #define ST40PCI_BASE_ADDRESS (0xb0000000) | ||
27 | #define ST40PCI_MEM_ADDRESS (ST40PCI_BASE_ADDRESS+0x0) | ||
28 | #define ST40PCI_IO_ADDRESS (ST40PCI_BASE_ADDRESS+0x06000000) | ||
29 | #define ST40PCI_REG_ADDRESS (ST40PCI_BASE_ADDRESS+0x07000000) | ||
30 | |||
31 | #define ST40PCI_REG(x) (ST40PCI_REG_ADDRESS+(ST40PCI_##x)) | ||
32 | #define ST40PCI_REG_INDEXED(reg, index) \ | ||
33 | (ST40PCI_REG(reg##0) + \ | ||
34 | ((ST40PCI_REG(reg##1) - ST40PCI_REG(reg##0))*index)) | ||
35 | |||
36 | #define ST40PCI_WRITE(reg,val) writel((val),ST40PCI_REG(reg)) | ||
37 | #define ST40PCI_WRITE_SHORT(reg,val) writew((val),ST40PCI_REG(reg)) | ||
38 | #define ST40PCI_WRITE_BYTE(reg,val) writeb((val),ST40PCI_REG(reg)) | ||
39 | #define ST40PCI_WRITE_INDEXED(reg, index, val) \ | ||
40 | writel((val), ST40PCI_REG_INDEXED(reg, index)); | ||
41 | |||
42 | #define ST40PCI_READ(reg) readl(ST40PCI_REG(reg)) | ||
43 | #define ST40PCI_READ_SHORT(reg) readw(ST40PCI_REG(reg)) | ||
44 | #define ST40PCI_READ_BYTE(reg) readb(ST40PCI_REG(reg)) | ||
45 | |||
46 | #define ST40PCI_SERR_IRQ 64 | ||
47 | #define ST40PCI_ERR_IRQ 65 | ||
48 | |||
49 | |||
50 | /* Macros to extract PLL params */ | ||
51 | #define PLL_MDIV(reg) ( ((unsigned)reg) & 0xff ) | ||
52 | #define PLL_NDIV(reg) ( (((unsigned)reg)>>8) & 0xff ) | ||
53 | #define PLL_PDIV(reg) ( (((unsigned)reg)>>16) & 0x3 ) | ||
54 | #define PLL_SETUP(reg) ( (((unsigned)reg)>>19) & 0x1ff ) | ||
55 | |||
56 | /* Build up the appropriate settings */ | ||
57 | #define PLL_SET(mdiv,ndiv,pdiv,setup) \ | ||
58 | ( ((mdiv)&0xff) | (((ndiv)&0xff)<<8) | (((pdiv)&3)<<16)| (((setup)&0x1ff)<<19)) | ||
59 | |||
60 | #define PLLPCICR (0xbb040000+0x10) | ||
61 | |||
62 | #define PLLPCICR_POWERON (1<<28) | ||
63 | #define PLLPCICR_OUT_EN (1<<29) | ||
64 | #define PLLPCICR_LOCKSELECT (1<<30) | ||
65 | #define PLLPCICR_LOCK (1<<31) | ||
66 | |||
67 | |||
68 | #define PLL_25MHZ 0x793c8512 | ||
69 | #define PLL_33MHZ PLL_SET(18,88,3,295) | ||
70 | |||
71 | static void pci_set_rbar_region(unsigned int region, unsigned long localAddr, | ||
72 | unsigned long pciOffset, unsigned long regionSize); | ||
73 | |||
74 | /* | ||
75 | * The pcibios_map_platform_irq function is defined in the appropriate | ||
76 | * board specific code and referenced here | ||
77 | */ | ||
78 | extern int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin); | ||
79 | |||
80 | static __init void SetPCIPLL(void) | ||
81 | { | ||
82 | { | ||
83 | /* Lets play with the PLL values */ | ||
84 | unsigned long pll1cr1; | ||
85 | unsigned long mdiv, ndiv, pdiv; | ||
86 | unsigned long muxcr; | ||
87 | unsigned int muxcr_ratios[4] = { 8, 16, 21, 1 }; | ||
88 | unsigned int freq; | ||
89 | |||
90 | #define CLKGENA 0xbb040000 | ||
91 | #define CLKGENA_PLL2_MUXCR CLKGENA + 0x48 | ||
92 | pll1cr1 = ctrl_inl(PLLPCICR); | ||
93 | printk("PLL1CR1 %08lx\n", pll1cr1); | ||
94 | mdiv = PLL_MDIV(pll1cr1); | ||
95 | ndiv = PLL_NDIV(pll1cr1); | ||
96 | pdiv = PLL_PDIV(pll1cr1); | ||
97 | printk("mdiv %02lx ndiv %02lx pdiv %02lx\n", mdiv, ndiv, pdiv); | ||
98 | freq = ((2*27*ndiv)/mdiv) / (1 << pdiv); | ||
99 | printk("PLL freq %dMHz\n", freq); | ||
100 | muxcr = ctrl_inl(CLKGENA_PLL2_MUXCR); | ||
101 | printk("PCI freq %dMhz\n", freq / muxcr_ratios[muxcr & 3]); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | struct pci_err { | ||
107 | unsigned mask; | ||
108 | const char *error_string; | ||
109 | }; | ||
110 | |||
111 | static struct pci_err int_error[]={ | ||
112 | { INT_MNLTDIM,"MNLTDIM: Master non-lock transfer"}, | ||
113 | { INT_TTADI, "TTADI: Illegal byte enable in I/O transfer"}, | ||
114 | { INT_TMTO, "TMTO: Target memory read/write timeout"}, | ||
115 | { INT_MDEI, "MDEI: Master function disable error"}, | ||
116 | { INT_APEDI, "APEDI: Address parity error"}, | ||
117 | { INT_SDI, "SDI: SERR detected"}, | ||
118 | { INT_DPEITW, "DPEITW: Data parity error target write"}, | ||
119 | { INT_PEDITR, "PEDITR: PERR detected"}, | ||
120 | { INT_TADIM, "TADIM: Target abort detected"}, | ||
121 | { INT_MADIM, "MADIM: Master abort detected"}, | ||
122 | { INT_MWPDI, "MWPDI: PERR from target at data write"}, | ||
123 | { INT_MRDPEI, "MRDPEI: Master read data parity error"} | ||
124 | }; | ||
125 | #define NUM_PCI_INT_ERRS (sizeof(int_error)/sizeof(struct pci_err)) | ||
126 | |||
127 | static struct pci_err aint_error[]={ | ||
128 | { AINT_MBI, "MBI: Master broken"}, | ||
129 | { AINT_TBTOI, "TBTOI: Target bus timeout"}, | ||
130 | { AINT_MBTOI, "MBTOI: Master bus timeout"}, | ||
131 | { AINT_TAI, "TAI: Target abort"}, | ||
132 | { AINT_MAI, "MAI: Master abort"}, | ||
133 | { AINT_RDPEI, "RDPEI: Read data parity"}, | ||
134 | { AINT_WDPE, "WDPE: Write data parity"} | ||
135 | }; | ||
136 | |||
137 | #define NUM_PCI_AINT_ERRS (sizeof(aint_error)/sizeof(struct pci_err)) | ||
138 | |||
139 | static void print_pci_errors(unsigned reg,struct pci_err *error,int num_errors) | ||
140 | { | ||
141 | int i; | ||
142 | |||
143 | for(i=0;i<num_errors;i++) { | ||
144 | if(reg & error[i].mask) { | ||
145 | printk("%s\n",error[i].error_string); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | } | ||
150 | |||
151 | |||
152 | static char * pci_commands[16]={ | ||
153 | "Int Ack", | ||
154 | "Special Cycle", | ||
155 | "I/O Read", | ||
156 | "I/O Write", | ||
157 | "Reserved", | ||
158 | "Reserved", | ||
159 | "Memory Read", | ||
160 | "Memory Write", | ||
161 | "Reserved", | ||
162 | "Reserved", | ||
163 | "Configuration Read", | ||
164 | "Configuration Write", | ||
165 | "Memory Read Multiple", | ||
166 | "Dual Address Cycle", | ||
167 | "Memory Read Line", | ||
168 | "Memory Write-and-Invalidate" | ||
169 | }; | ||
170 | |||
171 | static irqreturn_t st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs) | ||
172 | { | ||
173 | unsigned pci_int, pci_air, pci_cir, pci_aint; | ||
174 | static int count=0; | ||
175 | |||
176 | |||
177 | pci_int = ST40PCI_READ(INT);pci_aint = ST40PCI_READ(AINT); | ||
178 | pci_cir = ST40PCI_READ(CIR);pci_air = ST40PCI_READ(AIR); | ||
179 | |||
180 | /* Reset state to stop multiple interrupts */ | ||
181 | ST40PCI_WRITE(INT, ~0); ST40PCI_WRITE(AINT, ~0); | ||
182 | |||
183 | |||
184 | if(++count>1) return IRQ_HANDLED; | ||
185 | |||
186 | printk("** PCI ERROR **\n"); | ||
187 | |||
188 | if(pci_int) { | ||
189 | printk("** INT register status\n"); | ||
190 | print_pci_errors(pci_int,int_error,NUM_PCI_INT_ERRS); | ||
191 | } | ||
192 | |||
193 | if(pci_aint) { | ||
194 | printk("** AINT register status\n"); | ||
195 | print_pci_errors(pci_aint,aint_error,NUM_PCI_AINT_ERRS); | ||
196 | } | ||
197 | |||
198 | printk("** Address and command info\n"); | ||
199 | |||
200 | printk("** Command %s : Address 0x%x\n", | ||
201 | pci_commands[pci_cir&0xf],pci_air); | ||
202 | |||
203 | if(pci_cir&CIR_PIOTEM) { | ||
204 | printk("CIR_PIOTEM:PIO transfer error for master\n"); | ||
205 | } | ||
206 | if(pci_cir&CIR_RWTET) { | ||
207 | printk("CIR_RWTET:Read/Write transfer error for target\n"); | ||
208 | } | ||
209 | |||
210 | return IRQ_HANDLED; | ||
211 | } | ||
212 | |||
213 | |||
214 | /* Rounds a number UP to the nearest power of two. Used for | ||
215 | * sizing the PCI window. | ||
216 | */ | ||
217 | static u32 r2p2(u32 num) | ||
218 | { | ||
219 | int i = 31; | ||
220 | u32 tmp = num; | ||
221 | |||
222 | if (num == 0) | ||
223 | return 0; | ||
224 | |||
225 | do { | ||
226 | if (tmp & (1 << 31)) | ||
227 | break; | ||
228 | i--; | ||
229 | tmp <<= 1; | ||
230 | } while (i >= 0); | ||
231 | |||
232 | tmp = 1 << i; | ||
233 | /* If the original number isn't a power of 2, round it up */ | ||
234 | if (tmp != num) | ||
235 | tmp <<= 1; | ||
236 | |||
237 | return tmp; | ||
238 | } | ||
239 | |||
240 | static void __init pci_fixup_ide_bases(struct pci_dev *d) | ||
241 | { | ||
242 | int i; | ||
243 | |||
244 | /* | ||
245 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | ||
246 | */ | ||
247 | if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) | ||
248 | return; | ||
249 | printk("PCI: IDE base address fixup for %s\n", pci_name(d)); | ||
250 | for(i=0; i<4; i++) { | ||
251 | struct resource *r = &d->resource[i]; | ||
252 | if ((r->start & ~0x80) == 0x374) { | ||
253 | r->start |= 2; | ||
254 | r->end = r->start; | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); | ||
259 | |||
260 | int __init st40pci_init(unsigned memStart, unsigned memSize) | ||
261 | { | ||
262 | u32 lsr0; | ||
263 | |||
264 | SetPCIPLL(); | ||
265 | |||
266 | /* Initialises the ST40 pci subsystem, performing a reset, then programming | ||
267 | * up the address space decoders appropriately | ||
268 | */ | ||
269 | |||
270 | /* Should reset core here as well methink */ | ||
271 | |||
272 | ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_SOFT_RESET); | ||
273 | |||
274 | /* Loop while core resets */ | ||
275 | while (ST40PCI_READ(CR) & CR_SOFT_RESET); | ||
276 | |||
277 | /* Switch off interrupts */ | ||
278 | ST40PCI_WRITE(INTM, 0); | ||
279 | ST40PCI_WRITE(AINT, 0); | ||
280 | |||
281 | /* Now, lets reset all the cards on the bus with extreme prejudice */ | ||
282 | ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_RSTCTL); | ||
283 | udelay(250); | ||
284 | |||
285 | /* Set bus active, take it out of reset */ | ||
286 | ST40PCI_WRITE(CR, CR_LOCK_MASK | CR_BMAM | CR_CFINT | CR_PFCS | CR_PFE); | ||
287 | |||
288 | /* The PCI spec says that no access must be made to the bus until 1 second | ||
289 | * after reset. This seem ludicrously long, but some delay is needed here | ||
290 | */ | ||
291 | mdelay(1000); | ||
292 | |||
293 | /* Switch off interrupts */ | ||
294 | ST40PCI_WRITE(INTM, 0); | ||
295 | ST40PCI_WRITE(AINT, 0); | ||
296 | |||
297 | /* Allow it to be a master */ | ||
298 | |||
299 | ST40PCI_WRITE_SHORT(CSR_CMD, | ||
300 | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | ||
301 | PCI_COMMAND_IO); | ||
302 | |||
303 | /* Accesse to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000 | ||
304 | * on the PCI bus. This allows a nice 1-1 bus to phys mapping. | ||
305 | */ | ||
306 | |||
307 | |||
308 | ST40PCI_WRITE(MBR, 0x10000000); | ||
309 | /* Always set the max size 128M (actually, it is only 96MB wide) */ | ||
310 | ST40PCI_WRITE(MBMR, 0x07ff0000); | ||
311 | |||
312 | /* I/O addresses are mapped at 0xb6000000 -> 0xb7000000. These are changed to 0, to | ||
313 | * allow cards that have legacy io such as vga to function correctly. This gives a | ||
314 | * maximum of 64K of io/space as only the bottom 16 bits of the address are copied | ||
315 | * over to the bus when the transaction is made. 64K of io space is more than enough | ||
316 | */ | ||
317 | ST40PCI_WRITE(IOBR, 0x0); | ||
318 | /* Set up the 64K window */ | ||
319 | ST40PCI_WRITE(IOBMR, 0x0); | ||
320 | |||
321 | /* Now we set up the mbars so the PCI bus can see the local memory */ | ||
322 | /* Expose a 256M window starting at PCI address 0... */ | ||
323 | ST40PCI_WRITE(CSR_MBAR0, 0); | ||
324 | ST40PCI_WRITE(LSR0, 0x0fff0001); | ||
325 | |||
326 | /* ... and set up the initial incomming window to expose all of RAM */ | ||
327 | pci_set_rbar_region(7, memStart, memStart, memSize); | ||
328 | |||
329 | /* Maximise timeout values */ | ||
330 | ST40PCI_WRITE_BYTE(CSR_TRDY, 0xff); | ||
331 | ST40PCI_WRITE_BYTE(CSR_RETRY, 0xff); | ||
332 | ST40PCI_WRITE_BYTE(CSR_MIT, 0xff); | ||
333 | |||
334 | ST40PCI_WRITE_BYTE(PERF,PERF_MASTER_WRITE_POSTING); | ||
335 | |||
336 | return 1; | ||
337 | } | ||
338 | |||
339 | char * __init pcibios_setup(char *str) | ||
340 | { | ||
341 | return str; | ||
342 | } | ||
343 | |||
344 | |||
345 | #define SET_CONFIG_BITS(bus,devfn,where)\ | ||
346 | (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0)) | ||
347 | |||
348 | #define CONFIG_CMD(bus, devfn, where) SET_CONFIG_BITS(bus->number,devfn,where) | ||
349 | |||
350 | |||
351 | static int CheckForMasterAbort(void) | ||
352 | { | ||
353 | if (ST40PCI_READ(INT) & INT_MADIM) { | ||
354 | /* Should we clear config space version as well ??? */ | ||
355 | ST40PCI_WRITE(INT, INT_MADIM); | ||
356 | ST40PCI_WRITE_SHORT(CSR_STATUS, 0); | ||
357 | return 1; | ||
358 | } | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | /* Write to config register */ | ||
364 | static int st40pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) | ||
365 | { | ||
366 | ST40PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where)); | ||
367 | switch (size) { | ||
368 | case 1: | ||
369 | *val = (u8)ST40PCI_READ_BYTE(PDR + (where & 3)); | ||
370 | break; | ||
371 | case 2: | ||
372 | *val = (u16)ST40PCI_READ_SHORT(PDR + (where & 2)); | ||
373 | break; | ||
374 | case 4: | ||
375 | *val = ST40PCI_READ(PDR); | ||
376 | break; | ||
377 | } | ||
378 | |||
379 | if (CheckForMasterAbort()){ | ||
380 | switch (size) { | ||
381 | case 1: | ||
382 | *val = (u8)0xff; | ||
383 | break; | ||
384 | case 2: | ||
385 | *val = (u16)0xffff; | ||
386 | break; | ||
387 | case 4: | ||
388 | *val = 0xffffffff; | ||
389 | break; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | return PCIBIOS_SUCCESSFUL; | ||
394 | } | ||
395 | |||
396 | static int st40pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) | ||
397 | { | ||
398 | ST40PCI_WRITE(PAR, CONFIG_CMD(bus, devfn, where)); | ||
399 | |||
400 | switch (size) { | ||
401 | case 1: | ||
402 | ST40PCI_WRITE_BYTE(PDR + (where & 3), (u8)val); | ||
403 | break; | ||
404 | case 2: | ||
405 | ST40PCI_WRITE_SHORT(PDR + (where & 2), (u16)val); | ||
406 | break; | ||
407 | case 4: | ||
408 | ST40PCI_WRITE(PDR, val); | ||
409 | break; | ||
410 | } | ||
411 | |||
412 | CheckForMasterAbort(); | ||
413 | |||
414 | return PCIBIOS_SUCCESSFUL; | ||
415 | } | ||
416 | |||
417 | struct pci_ops st40pci_config_ops = { | ||
418 | .read = st40pci_read, | ||
419 | .write = st40pci_write, | ||
420 | }; | ||
421 | |||
422 | |||
423 | /* Everything hangs off this */ | ||
424 | static struct pci_bus *pci_root_bus; | ||
425 | |||
426 | |||
427 | static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin) | ||
428 | { | ||
429 | return PCI_SLOT(dev->devfn); | ||
430 | } | ||
431 | |||
432 | |||
433 | static int __init pcibios_init(void) | ||
434 | { | ||
435 | extern unsigned long memory_start, memory_end; | ||
436 | |||
437 | printk(KERN_ALERT "pci-st40.c: pcibios_init\n"); | ||
438 | |||
439 | if (sh_mv.mv_init_pci != NULL) { | ||
440 | sh_mv.mv_init_pci(); | ||
441 | } | ||
442 | |||
443 | /* The pci subsytem needs to know where memory is and how much | ||
444 | * of it there is. I've simply made these globals. A better mechanism | ||
445 | * is probably needed. | ||
446 | */ | ||
447 | st40pci_init(PHYSADDR(memory_start), | ||
448 | PHYSADDR(memory_end) - PHYSADDR(memory_start)); | ||
449 | |||
450 | if (request_irq(ST40PCI_ERR_IRQ, st40_pci_irq, | ||
451 | SA_INTERRUPT, "st40pci", NULL)) { | ||
452 | printk(KERN_ERR "st40pci: Cannot hook interrupt\n"); | ||
453 | return -EIO; | ||
454 | } | ||
455 | |||
456 | /* Enable the PCI interrupts on the device */ | ||
457 | ST40PCI_WRITE(INTM, ~0); | ||
458 | ST40PCI_WRITE(AINT, ~0); | ||
459 | |||
460 | /* Map the io address apprioately */ | ||
461 | #ifdef CONFIG_HD64465 | ||
462 | hd64465_port_map(PCIBIOS_MIN_IO, (64 * 1024) - PCIBIOS_MIN_IO + 1, | ||
463 | ST40_IO_ADDR + PCIBIOS_MIN_IO, 0); | ||
464 | #endif | ||
465 | |||
466 | /* ok, do the scan man */ | ||
467 | pci_root_bus = pci_scan_bus(0, &st40pci_config_ops, NULL); | ||
468 | pci_assign_unassigned_resources(); | ||
469 | pci_fixup_irqs(no_swizzle, pcibios_map_platform_irq); | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | subsys_initcall(pcibios_init); | ||
475 | |||
476 | void __init pcibios_fixup_bus(struct pci_bus *bus) | ||
477 | { | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * Publish a region of local address space over the PCI bus | ||
482 | * to other devices. | ||
483 | */ | ||
484 | static void pci_set_rbar_region(unsigned int region, unsigned long localAddr, | ||
485 | unsigned long pciOffset, unsigned long regionSize) | ||
486 | { | ||
487 | unsigned long mask; | ||
488 | |||
489 | if (region > 7) | ||
490 | return; | ||
491 | |||
492 | if (regionSize > (512 * 1024 * 1024)) | ||
493 | return; | ||
494 | |||
495 | mask = r2p2(regionSize) - 0x10000; | ||
496 | |||
497 | /* Diable the region (in case currently in use, should never happen) */ | ||
498 | ST40PCI_WRITE_INDEXED(RSR, region, 0); | ||
499 | |||
500 | /* Start of local address space to publish */ | ||
501 | ST40PCI_WRITE_INDEXED(RLAR, region, PHYSADDR(localAddr) ); | ||
502 | |||
503 | /* Start of region in PCI address space as an offset from MBAR0 */ | ||
504 | ST40PCI_WRITE_INDEXED(RBAR, region, pciOffset); | ||
505 | |||
506 | /* Size of region */ | ||
507 | ST40PCI_WRITE_INDEXED(RSR, region, mask | 1); | ||
508 | } | ||
509 | |||
diff --git a/arch/sh/drivers/pci/pci-st40.h b/arch/sh/drivers/pci/pci-st40.h new file mode 100644 index 000000000000..d729e0c2d5fe --- /dev/null +++ b/arch/sh/drivers/pci/pci-st40.h | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 David J. Mckay (david.mckay@st.com) | ||
3 | * | ||
4 | * May be copied or modified under the terms of the GNU General Public | ||
5 | * License. See linux/COPYING for more information. | ||
6 | * | ||
7 | * Defintions for the ST40 PCI hardware. | ||
8 | */ | ||
9 | |||
10 | #ifndef __PCI_ST40_H__ | ||
11 | #define __PCI_ST40_H__ | ||
12 | |||
13 | #define ST40PCI_VCR_STATUS 0x00 | ||
14 | |||
15 | #define ST40PCI_VCR_VERSION 0x08 | ||
16 | |||
17 | #define ST40PCI_CR 0x10 | ||
18 | |||
19 | #define CR_SOFT_RESET (1<<12) | ||
20 | #define CR_PFCS (1<<11) | ||
21 | #define CR_PFE (1<<9) | ||
22 | #define CR_BMAM (1<<6) | ||
23 | #define CR_HOST (1<<5) | ||
24 | #define CR_CLKEN (1<<4) | ||
25 | #define CR_SOCS (1<<3) | ||
26 | #define CR_IOCS (1<<2) | ||
27 | #define CR_RSTCTL (1<<1) | ||
28 | #define CR_CFINT (1<<0) | ||
29 | #define CR_LOCK_MASK 0x5a000000 | ||
30 | |||
31 | |||
32 | #define ST40PCI_LSR0 0X14 | ||
33 | #define ST40PCI_LAR0 0x1c | ||
34 | |||
35 | #define ST40PCI_INT 0x24 | ||
36 | #define INT_MNLTDIM (1<<15) | ||
37 | #define INT_TTADI (1<<14) | ||
38 | #define INT_TMTO (1<<9) | ||
39 | #define INT_MDEI (1<<8) | ||
40 | #define INT_APEDI (1<<7) | ||
41 | #define INT_SDI (1<<6) | ||
42 | #define INT_DPEITW (1<<5) | ||
43 | #define INT_PEDITR (1<<4) | ||
44 | #define INT_TADIM (1<<3) | ||
45 | #define INT_MADIM (1<<2) | ||
46 | #define INT_MWPDI (1<<1) | ||
47 | #define INT_MRDPEI (1<<0) | ||
48 | |||
49 | |||
50 | #define ST40PCI_INTM 0x28 | ||
51 | #define ST40PCI_AIR 0x2c | ||
52 | |||
53 | #define ST40PCI_CIR 0x30 | ||
54 | #define CIR_PIOTEM (1<<31) | ||
55 | #define CIR_RWTET (1<<26) | ||
56 | |||
57 | #define ST40PCI_AINT 0x40 | ||
58 | #define AINT_MBI (1<<13) | ||
59 | #define AINT_TBTOI (1<<12) | ||
60 | #define AINT_MBTOI (1<<11) | ||
61 | #define AINT_TAI (1<<3) | ||
62 | #define AINT_MAI (1<<2) | ||
63 | #define AINT_RDPEI (1<<1) | ||
64 | #define AINT_WDPE (1<<0) | ||
65 | |||
66 | #define ST40PCI_AINTM 0x44 | ||
67 | #define ST40PCI_BMIR 0x48 | ||
68 | #define ST40PCI_PAR 0x4c | ||
69 | #define ST40PCI_MBR 0x50 | ||
70 | #define ST40PCI_IOBR 0x54 | ||
71 | #define ST40PCI_PINT 0x58 | ||
72 | #define ST40PCI_PINTM 0x5c | ||
73 | #define ST40PCI_MBMR 0x70 | ||
74 | #define ST40PCI_IOBMR 0x74 | ||
75 | #define ST40PCI_PDR 0x78 | ||
76 | |||
77 | /* H8 specific registers start here */ | ||
78 | #define ST40PCI_WCBAR 0x7c | ||
79 | #define ST40PCI_LOCCFG_UNLOCK 0x34 | ||
80 | |||
81 | #define ST40PCI_RBAR0 0x100 | ||
82 | #define ST40PCI_RSR0 0x104 | ||
83 | #define ST40PCI_RLAR0 0x108 | ||
84 | |||
85 | #define ST40PCI_RBAR1 0x110 | ||
86 | #define ST40PCI_RSR1 0x114 | ||
87 | #define ST40PCI_RLAR1 0x118 | ||
88 | |||
89 | |||
90 | #define ST40PCI_RBAR2 0x120 | ||
91 | #define ST40PCI_RSR2 0x124 | ||
92 | #define ST40PCI_RLAR2 0x128 | ||
93 | |||
94 | #define ST40PCI_RBAR3 0x130 | ||
95 | #define ST40PCI_RSR3 0x134 | ||
96 | #define ST40PCI_RLAR3 0x138 | ||
97 | |||
98 | #define ST40PCI_RBAR4 0x140 | ||
99 | #define ST40PCI_RSR4 0x144 | ||
100 | #define ST40PCI_RLAR4 0x148 | ||
101 | |||
102 | #define ST40PCI_RBAR5 0x150 | ||
103 | #define ST40PCI_RSR5 0x154 | ||
104 | #define ST40PCI_RLAR5 0x158 | ||
105 | |||
106 | #define ST40PCI_RBAR6 0x160 | ||
107 | #define ST40PCI_RSR6 0x164 | ||
108 | #define ST40PCI_RLAR6 0x168 | ||
109 | |||
110 | #define ST40PCI_RBAR7 0x170 | ||
111 | #define ST40PCI_RSR7 0x174 | ||
112 | #define ST40PCI_RLAR7 0x178 | ||
113 | |||
114 | |||
115 | #define ST40PCI_RBAR(n) (0x100+(0x10*(n))) | ||
116 | #define ST40PCI_RSR(n) (0x104+(0x10*(n))) | ||
117 | #define ST40PCI_RLAR(n) (0x108+(0x10*(n))) | ||
118 | |||
119 | #define ST40PCI_PERF 0x80 | ||
120 | #define PERF_MASTER_WRITE_POSTING (1<<4) | ||
121 | /* H8 specific registers end here */ | ||
122 | |||
123 | |||
124 | /* These are configs space registers */ | ||
125 | #define ST40PCI_CSR_VID 0x10000 | ||
126 | #define ST40PCI_CSR_DID 0x10002 | ||
127 | #define ST40PCI_CSR_CMD 0x10004 | ||
128 | #define ST40PCI_CSR_STATUS 0x10006 | ||
129 | #define ST40PCI_CSR_MBAR0 0x10010 | ||
130 | #define ST40PCI_CSR_TRDY 0x10040 | ||
131 | #define ST40PCI_CSR_RETRY 0x10041 | ||
132 | #define ST40PCI_CSR_MIT 0x1000d | ||
133 | |||
134 | #define ST40_IO_ADDR 0xb6000000 | ||
135 | |||
136 | #endif /* __PCI_ST40_H__ */ | ||
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c new file mode 100644 index 000000000000..c1669905abe4 --- /dev/null +++ b/arch/sh/drivers/pci/pci.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* arch/sh/kernel/pci.c | ||
2 | * $Id: pci.c,v 1.1 2003/08/24 19:15:45 lethal Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2002 M. R. Brown <mrbrown@linux-sh.org> | ||
5 | * | ||
6 | * | ||
7 | * These functions are collected here to reduce duplication of common | ||
8 | * code amongst the many platform-specific PCI support code files. | ||
9 | * | ||
10 | * These routines require the following board-specific routines: | ||
11 | * void pcibios_fixup_irqs(); | ||
12 | * | ||
13 | * See include/asm-sh/pci.h for more information. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/pci.h> | ||
18 | #include <linux/init.h> | ||
19 | |||
20 | static int __init pcibios_init(void) | ||
21 | { | ||
22 | struct pci_channel *p; | ||
23 | struct pci_bus *bus; | ||
24 | int busno; | ||
25 | |||
26 | #ifdef CONFIG_PCI_AUTO | ||
27 | /* assign resources */ | ||
28 | busno = 0; | ||
29 | for (p = board_pci_channels; p->pci_ops != NULL; p++) { | ||
30 | busno = pciauto_assign_resources(busno, p) + 1; | ||
31 | } | ||
32 | #endif | ||
33 | |||
34 | /* scan the buses */ | ||
35 | busno = 0; | ||
36 | for (p= board_pci_channels; p->pci_ops != NULL; p++) { | ||
37 | bus = pci_scan_bus(busno, p->pci_ops, p); | ||
38 | busno = bus->subordinate+1; | ||
39 | } | ||
40 | |||
41 | /* board-specific fixups */ | ||
42 | pcibios_fixup_irqs(); | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | subsys_initcall(pcibios_init); | ||
48 | |||
49 | void | ||
50 | pcibios_update_resource(struct pci_dev *dev, struct resource *root, | ||
51 | struct resource *res, int resource) | ||
52 | { | ||
53 | u32 new, check; | ||
54 | int reg; | ||
55 | |||
56 | new = res->start | (res->flags & PCI_REGION_FLAG_MASK); | ||
57 | if (resource < 6) { | ||
58 | reg = PCI_BASE_ADDRESS_0 + 4*resource; | ||
59 | } else if (resource == PCI_ROM_RESOURCE) { | ||
60 | res->flags |= IORESOURCE_ROM_ENABLE; | ||
61 | new |= PCI_ROM_ADDRESS_ENABLE; | ||
62 | reg = dev->rom_base_reg; | ||
63 | } else { | ||
64 | /* Somebody might have asked allocation of a non-standard resource */ | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | pci_write_config_dword(dev, reg, new); | ||
69 | pci_read_config_dword(dev, reg, &check); | ||
70 | if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { | ||
71 | printk(KERN_ERR "PCI: Error while updating region " | ||
72 | "%s/%d (%08x != %08x)\n", pci_name(dev), resource, | ||
73 | new, check); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | void pcibios_align_resource(void *data, struct resource *res, | ||
78 | unsigned long size, unsigned long align) | ||
79 | __attribute__ ((weak)); | ||
80 | |||
81 | /* | ||
82 | * We need to avoid collisions with `mirrored' VGA ports | ||
83 | * and other strange ISA hardware, so we always want the | ||
84 | * addresses to be allocated in the 0x000-0x0ff region | ||
85 | * modulo 0x400. | ||
86 | */ | ||
87 | void pcibios_align_resource(void *data, struct resource *res, | ||
88 | unsigned long size, unsigned long align) | ||
89 | { | ||
90 | if (res->flags & IORESOURCE_IO) { | ||
91 | unsigned long start = res->start; | ||
92 | |||
93 | if (start & 0x300) { | ||
94 | start = (start + 0x3ff) & ~0x3ff; | ||
95 | res->start = start; | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | int pcibios_enable_device(struct pci_dev *dev, int mask) | ||
101 | { | ||
102 | u16 cmd, old_cmd; | ||
103 | int idx; | ||
104 | struct resource *r; | ||
105 | |||
106 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
107 | old_cmd = cmd; | ||
108 | for(idx=0; idx<6; idx++) { | ||
109 | if (!(mask & (1 << idx))) | ||
110 | continue; | ||
111 | r = &dev->resource[idx]; | ||
112 | if (!r->start && r->end) { | ||
113 | printk(KERN_ERR "PCI: Device %s not available because " | ||
114 | "of resource collisions\n", pci_name(dev)); | ||
115 | return -EINVAL; | ||
116 | } | ||
117 | if (r->flags & IORESOURCE_IO) | ||
118 | cmd |= PCI_COMMAND_IO; | ||
119 | if (r->flags & IORESOURCE_MEM) | ||
120 | cmd |= PCI_COMMAND_MEMORY; | ||
121 | } | ||
122 | if (dev->resource[PCI_ROM_RESOURCE].start) | ||
123 | cmd |= PCI_COMMAND_MEMORY; | ||
124 | if (cmd != old_cmd) { | ||
125 | printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", | ||
126 | pci_name(dev), old_cmd, cmd); | ||
127 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
128 | } | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * If we set up a device for bus mastering, we need to check and set | ||
134 | * the latency timer as it may not be properly set. | ||
135 | */ | ||
136 | unsigned int pcibios_max_latency = 255; | ||
137 | |||
138 | void pcibios_set_master(struct pci_dev *dev) | ||
139 | { | ||
140 | u8 lat; | ||
141 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); | ||
142 | if (lat < 16) | ||
143 | lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; | ||
144 | else if (lat > pcibios_max_latency) | ||
145 | lat = pcibios_max_latency; | ||
146 | else | ||
147 | return; | ||
148 | printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); | ||
149 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
150 | } | ||
151 | |||
152 | void __init pcibios_update_irq(struct pci_dev *dev, int irq) | ||
153 | { | ||
154 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); | ||
155 | } | ||