diff options
Diffstat (limited to 'arch/frv/mb93090-mb00')
-rw-r--r-- | arch/frv/mb93090-mb00/Makefile | 13 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-dma-nommu.c | 152 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-dma.c | 105 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-frv.c | 288 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-frv.h | 47 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-irq.c | 70 | ||||
-rw-r--r-- | arch/frv/mb93090-mb00/pci-vdk.c | 467 |
7 files changed, 1142 insertions, 0 deletions
diff --git a/arch/frv/mb93090-mb00/Makefile b/arch/frv/mb93090-mb00/Makefile new file mode 100644 index 000000000000..3faf0f8cf9b5 --- /dev/null +++ b/arch/frv/mb93090-mb00/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for the MB93090-MB00 motherboard stuff | ||
3 | # | ||
4 | |||
5 | ifeq "$(CONFIG_PCI)" "y" | ||
6 | obj-y := pci-frv.o pci-irq.o pci-vdk.o | ||
7 | |||
8 | ifeq "$(CONFIG_MMU)" "y" | ||
9 | obj-y += pci-dma.o | ||
10 | else | ||
11 | obj-y += pci-dma-nommu.o | ||
12 | endif | ||
13 | endif | ||
diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c new file mode 100644 index 000000000000..819895cf0b9e --- /dev/null +++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* pci-dma-nommu.c: Dynamic DMA mapping support for the FRV | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Woodhouse (dwmw2@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #if 1 | ||
20 | #define DMA_SRAM_START dma_coherent_mem_start | ||
21 | #define DMA_SRAM_END dma_coherent_mem_end | ||
22 | #else // Use video RAM on Matrox | ||
23 | #define DMA_SRAM_START 0xe8900000 | ||
24 | #define DMA_SRAM_END 0xe8a00000 | ||
25 | #endif | ||
26 | |||
27 | struct dma_alloc_record { | ||
28 | struct list_head list; | ||
29 | unsigned long ofs; | ||
30 | unsigned long len; | ||
31 | }; | ||
32 | |||
33 | static DEFINE_SPINLOCK(dma_alloc_lock); | ||
34 | static LIST_HEAD(dma_alloc_list); | ||
35 | |||
36 | void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, int gfp) | ||
37 | { | ||
38 | struct dma_alloc_record *new; | ||
39 | struct list_head *this = &dma_alloc_list; | ||
40 | unsigned long flags; | ||
41 | unsigned long start = DMA_SRAM_START; | ||
42 | unsigned long end; | ||
43 | |||
44 | if (!DMA_SRAM_START) { | ||
45 | printk("%s called without any DMA area reserved!\n", __func__); | ||
46 | return NULL; | ||
47 | } | ||
48 | |||
49 | new = kmalloc(sizeof (*new), GFP_ATOMIC); | ||
50 | if (!new) | ||
51 | return NULL; | ||
52 | |||
53 | /* Round up to a reasonable alignment */ | ||
54 | new->len = (size + 31) & ~31; | ||
55 | |||
56 | spin_lock_irqsave(&dma_alloc_lock, flags); | ||
57 | |||
58 | list_for_each (this, &dma_alloc_list) { | ||
59 | struct dma_alloc_record *this_r = list_entry(this, struct dma_alloc_record, list); | ||
60 | end = this_r->ofs; | ||
61 | |||
62 | if (end - start >= size) | ||
63 | goto gotone; | ||
64 | |||
65 | start = this_r->ofs + this_r->len; | ||
66 | } | ||
67 | /* Reached end of list. */ | ||
68 | end = DMA_SRAM_END; | ||
69 | this = &dma_alloc_list; | ||
70 | |||
71 | if (end - start >= size) { | ||
72 | gotone: | ||
73 | new->ofs = start; | ||
74 | list_add_tail(&new->list, this); | ||
75 | spin_unlock_irqrestore(&dma_alloc_lock, flags); | ||
76 | |||
77 | *dma_handle = start; | ||
78 | return (void *)start; | ||
79 | } | ||
80 | |||
81 | kfree(new); | ||
82 | spin_unlock_irqrestore(&dma_alloc_lock, flags); | ||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) | ||
87 | { | ||
88 | struct dma_alloc_record *rec; | ||
89 | unsigned long flags; | ||
90 | |||
91 | spin_lock_irqsave(&dma_alloc_lock, flags); | ||
92 | |||
93 | list_for_each_entry(rec, &dma_alloc_list, list) { | ||
94 | if (rec->ofs == dma_handle) { | ||
95 | list_del(&rec->list); | ||
96 | kfree(rec); | ||
97 | spin_unlock_irqrestore(&dma_alloc_lock, flags); | ||
98 | return; | ||
99 | } | ||
100 | } | ||
101 | spin_unlock_irqrestore(&dma_alloc_lock, flags); | ||
102 | BUG(); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Map a single buffer of the indicated size for DMA in streaming mode. | ||
107 | * The 32-bit bus address to use is returned. | ||
108 | * | ||
109 | * Once the device is given the dma address, the device owns this memory | ||
110 | * until either pci_unmap_single or pci_dma_sync_single is performed. | ||
111 | */ | ||
112 | dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, | ||
113 | enum dma_data_direction direction) | ||
114 | { | ||
115 | if (direction == DMA_NONE) | ||
116 | BUG(); | ||
117 | |||
118 | frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size); | ||
119 | |||
120 | return virt_to_bus(ptr); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Map a set of buffers described by scatterlist in streaming | ||
125 | * mode for DMA. This is the scather-gather version of the | ||
126 | * above pci_map_single interface. Here the scatter gather list | ||
127 | * elements are each tagged with the appropriate dma address | ||
128 | * and length. They are obtained via sg_dma_{address,length}(SG). | ||
129 | * | ||
130 | * NOTE: An implementation may be able to use a smaller number of | ||
131 | * DMA address/length pairs than there are SG table elements. | ||
132 | * (for example via virtual mapping capabilities) | ||
133 | * The routine returns the number of addr/length pairs actually | ||
134 | * used, at most nents. | ||
135 | * | ||
136 | * Device ownership issues as mentioned above for pci_map_single are | ||
137 | * the same here. | ||
138 | */ | ||
139 | int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, | ||
140 | enum dma_data_direction direction) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | for (i=0; i<nents; i++) | ||
145 | frv_cache_wback_inv(sg_dma_address(&sg[i]), | ||
146 | sg_dma_address(&sg[i]) + sg_dma_len(&sg[i])); | ||
147 | |||
148 | if (direction == DMA_NONE) | ||
149 | BUG(); | ||
150 | |||
151 | return nents; | ||
152 | } | ||
diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c new file mode 100644 index 000000000000..27eb12066507 --- /dev/null +++ b/arch/frv/mb93090-mb00/pci-dma.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* pci-dma.c: Dynamic DMA mapping support for the FRV CPUs that have MMUs | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/highmem.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, int gfp) | ||
21 | { | ||
22 | void *ret; | ||
23 | |||
24 | ret = consistent_alloc(gfp, size, dma_handle); | ||
25 | if (ret) | ||
26 | memset(ret, 0, size); | ||
27 | |||
28 | return ret; | ||
29 | } | ||
30 | |||
31 | void dma_free_coherent(struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) | ||
32 | { | ||
33 | consistent_free(vaddr); | ||
34 | } | ||
35 | |||
36 | /* | ||
37 | * Map a single buffer of the indicated size for DMA in streaming mode. | ||
38 | * The 32-bit bus address to use is returned. | ||
39 | * | ||
40 | * Once the device is given the dma address, the device owns this memory | ||
41 | * until either pci_unmap_single or pci_dma_sync_single is performed. | ||
42 | */ | ||
43 | dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, | ||
44 | enum dma_data_direction direction) | ||
45 | { | ||
46 | if (direction == DMA_NONE) | ||
47 | BUG(); | ||
48 | |||
49 | frv_cache_wback_inv((unsigned long) ptr, (unsigned long) ptr + size); | ||
50 | |||
51 | return virt_to_bus(ptr); | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * Map a set of buffers described by scatterlist in streaming | ||
56 | * mode for DMA. This is the scather-gather version of the | ||
57 | * above pci_map_single interface. Here the scatter gather list | ||
58 | * elements are each tagged with the appropriate dma address | ||
59 | * and length. They are obtained via sg_dma_{address,length}(SG). | ||
60 | * | ||
61 | * NOTE: An implementation may be able to use a smaller number of | ||
62 | * DMA address/length pairs than there are SG table elements. | ||
63 | * (for example via virtual mapping capabilities) | ||
64 | * The routine returns the number of addr/length pairs actually | ||
65 | * used, at most nents. | ||
66 | * | ||
67 | * Device ownership issues as mentioned above for pci_map_single are | ||
68 | * the same here. | ||
69 | */ | ||
70 | int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, | ||
71 | enum dma_data_direction direction) | ||
72 | { | ||
73 | unsigned long dampr2; | ||
74 | void *vaddr; | ||
75 | int i; | ||
76 | |||
77 | if (direction == DMA_NONE) | ||
78 | BUG(); | ||
79 | |||
80 | dampr2 = __get_DAMPR(2); | ||
81 | |||
82 | for (i = 0; i < nents; i++) { | ||
83 | vaddr = kmap_atomic(sg[i].page, __KM_CACHE); | ||
84 | |||
85 | frv_dcache_writeback((unsigned long) vaddr, | ||
86 | (unsigned long) vaddr + PAGE_SIZE); | ||
87 | |||
88 | } | ||
89 | |||
90 | kunmap_atomic(vaddr, __KM_CACHE); | ||
91 | if (dampr2) { | ||
92 | __set_DAMPR(2, dampr2); | ||
93 | __set_IAMPR(2, dampr2); | ||
94 | } | ||
95 | |||
96 | return nents; | ||
97 | } | ||
98 | |||
99 | dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, | ||
100 | size_t size, enum dma_data_direction direction) | ||
101 | { | ||
102 | BUG_ON(direction == DMA_NONE); | ||
103 | flush_dcache_page(page); | ||
104 | return (dma_addr_t) page_to_phys(page) + offset; | ||
105 | } | ||
diff --git a/arch/frv/mb93090-mb00/pci-frv.c b/arch/frv/mb93090-mb00/pci-frv.c new file mode 100644 index 000000000000..83e5489cf039 --- /dev/null +++ b/arch/frv/mb93090-mb00/pci-frv.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* pci-frv.c: low-level PCI access routines | ||
2 | * | ||
3 | * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * - Derived from the i386 equivalent stuff | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/ioport.h> | ||
18 | #include <linux/errno.h> | ||
19 | |||
20 | #include "pci-frv.h" | ||
21 | |||
22 | #if 0 | ||
23 | void | ||
24 | pcibios_update_resource(struct pci_dev *dev, struct resource *root, | ||
25 | struct resource *res, int resource) | ||
26 | { | ||
27 | u32 new, check; | ||
28 | int reg; | ||
29 | |||
30 | new = res->start | (res->flags & PCI_REGION_FLAG_MASK); | ||
31 | if (resource < 6) { | ||
32 | reg = PCI_BASE_ADDRESS_0 + 4*resource; | ||
33 | } else if (resource == PCI_ROM_RESOURCE) { | ||
34 | res->flags |= IORESOURCE_ROM_ENABLE; | ||
35 | new |= PCI_ROM_ADDRESS_ENABLE; | ||
36 | reg = dev->rom_base_reg; | ||
37 | } else { | ||
38 | /* Somebody might have asked allocation of a non-standard resource */ | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | pci_write_config_dword(dev, reg, new); | ||
43 | pci_read_config_dword(dev, reg, &check); | ||
44 | if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { | ||
45 | printk(KERN_ERR "PCI: Error while updating region " | ||
46 | "%s/%d (%08x != %08x)\n", pci_name(dev), resource, | ||
47 | new, check); | ||
48 | } | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | /* | ||
53 | * We need to avoid collisions with `mirrored' VGA ports | ||
54 | * and other strange ISA hardware, so we always want the | ||
55 | * addresses to be allocated in the 0x000-0x0ff region | ||
56 | * modulo 0x400. | ||
57 | * | ||
58 | * Why? Because some silly external IO cards only decode | ||
59 | * the low 10 bits of the IO address. The 0x00-0xff region | ||
60 | * is reserved for motherboard devices that decode all 16 | ||
61 | * bits, so it's ok to allocate at, say, 0x2800-0x28ff, | ||
62 | * but we want to try to avoid allocating at 0x2900-0x2bff | ||
63 | * which might have be mirrored at 0x0100-0x03ff.. | ||
64 | */ | ||
65 | void | ||
66 | pcibios_align_resource(void *data, struct resource *res, | ||
67 | unsigned long size, unsigned long align) | ||
68 | { | ||
69 | if (res->flags & IORESOURCE_IO) { | ||
70 | unsigned long start = res->start; | ||
71 | |||
72 | if (start & 0x300) { | ||
73 | start = (start + 0x3ff) & ~0x3ff; | ||
74 | res->start = start; | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | |||
79 | |||
80 | /* | ||
81 | * Handle resources of PCI devices. If the world were perfect, we could | ||
82 | * just allocate all the resource regions and do nothing more. It isn't. | ||
83 | * On the other hand, we cannot just re-allocate all devices, as it would | ||
84 | * require us to know lots of host bridge internals. So we attempt to | ||
85 | * keep as much of the original configuration as possible, but tweak it | ||
86 | * when it's found to be wrong. | ||
87 | * | ||
88 | * Known BIOS problems we have to work around: | ||
89 | * - I/O or memory regions not configured | ||
90 | * - regions configured, but not enabled in the command register | ||
91 | * - bogus I/O addresses above 64K used | ||
92 | * - expansion ROMs left enabled (this may sound harmless, but given | ||
93 | * the fact the PCI specs explicitly allow address decoders to be | ||
94 | * shared between expansion ROMs and other resource regions, it's | ||
95 | * at least dangerous) | ||
96 | * | ||
97 | * Our solution: | ||
98 | * (1) Allocate resources for all buses behind PCI-to-PCI bridges. | ||
99 | * This gives us fixed barriers on where we can allocate. | ||
100 | * (2) Allocate resources for all enabled devices. If there is | ||
101 | * a collision, just mark the resource as unallocated. Also | ||
102 | * disable expansion ROMs during this step. | ||
103 | * (3) Try to allocate resources for disabled devices. If the | ||
104 | * resources were assigned correctly, everything goes well, | ||
105 | * if they weren't, they won't disturb allocation of other | ||
106 | * resources. | ||
107 | * (4) Assign new addresses to resources which were either | ||
108 | * not configured at all or misconfigured. If explicitly | ||
109 | * requested by the user, configure expansion ROM address | ||
110 | * as well. | ||
111 | */ | ||
112 | |||
113 | static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | ||
114 | { | ||
115 | struct list_head *ln; | ||
116 | struct pci_bus *bus; | ||
117 | struct pci_dev *dev; | ||
118 | int idx; | ||
119 | struct resource *r, *pr; | ||
120 | |||
121 | /* Depth-First Search on bus tree */ | ||
122 | for (ln=bus_list->next; ln != bus_list; ln=ln->next) { | ||
123 | bus = pci_bus_b(ln); | ||
124 | if ((dev = bus->self)) { | ||
125 | for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { | ||
126 | r = &dev->resource[idx]; | ||
127 | if (!r->start) | ||
128 | continue; | ||
129 | pr = pci_find_parent_resource(dev, r); | ||
130 | if (!pr || request_resource(pr, r) < 0) | ||
131 | printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev)); | ||
132 | } | ||
133 | } | ||
134 | pcibios_allocate_bus_resources(&bus->children); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | static void __init pcibios_allocate_resources(int pass) | ||
139 | { | ||
140 | struct pci_dev *dev = NULL; | ||
141 | int idx, disabled; | ||
142 | u16 command; | ||
143 | struct resource *r, *pr; | ||
144 | |||
145 | while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev), | ||
146 | dev != NULL | ||
147 | ) { | ||
148 | pci_read_config_word(dev, PCI_COMMAND, &command); | ||
149 | for(idx = 0; idx < 6; idx++) { | ||
150 | r = &dev->resource[idx]; | ||
151 | if (r->parent) /* Already allocated */ | ||
152 | continue; | ||
153 | if (!r->start) /* Address not assigned at all */ | ||
154 | continue; | ||
155 | if (r->flags & IORESOURCE_IO) | ||
156 | disabled = !(command & PCI_COMMAND_IO); | ||
157 | else | ||
158 | disabled = !(command & PCI_COMMAND_MEMORY); | ||
159 | if (pass == disabled) { | ||
160 | DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", | ||
161 | r->start, r->end, r->flags, disabled, pass); | ||
162 | pr = pci_find_parent_resource(dev, r); | ||
163 | if (!pr || request_resource(pr, r) < 0) { | ||
164 | printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, pci_name(dev)); | ||
165 | /* We'll assign a new address later */ | ||
166 | r->end -= r->start; | ||
167 | r->start = 0; | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | if (!pass) { | ||
172 | r = &dev->resource[PCI_ROM_RESOURCE]; | ||
173 | if (r->flags & IORESOURCE_ROM_ENABLE) { | ||
174 | /* Turn the ROM off, leave the resource region, but keep it unregistered. */ | ||
175 | u32 reg; | ||
176 | DBG("PCI: Switching off ROM of %s\n", pci_name(dev)); | ||
177 | r->flags &= ~IORESOURCE_ROM_ENABLE; | ||
178 | pci_read_config_dword(dev, dev->rom_base_reg, ®); | ||
179 | pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void __init pcibios_assign_resources(void) | ||
186 | { | ||
187 | struct pci_dev *dev = NULL; | ||
188 | int idx; | ||
189 | struct resource *r; | ||
190 | |||
191 | while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev), | ||
192 | dev != NULL | ||
193 | ) { | ||
194 | int class = dev->class >> 8; | ||
195 | |||
196 | /* Don't touch classless devices and host bridges */ | ||
197 | if (!class || class == PCI_CLASS_BRIDGE_HOST) | ||
198 | continue; | ||
199 | |||
200 | for(idx=0; idx<6; idx++) { | ||
201 | r = &dev->resource[idx]; | ||
202 | |||
203 | /* | ||
204 | * Don't touch IDE controllers and I/O ports of video cards! | ||
205 | */ | ||
206 | if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || | ||
207 | (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) | ||
208 | continue; | ||
209 | |||
210 | /* | ||
211 | * We shall assign a new address to this resource, either because | ||
212 | * the BIOS forgot to do so or because we have decided the old | ||
213 | * address was unusable for some reason. | ||
214 | */ | ||
215 | if (!r->start && r->end) | ||
216 | pci_assign_resource(dev, idx); | ||
217 | } | ||
218 | |||
219 | if (pci_probe & PCI_ASSIGN_ROMS) { | ||
220 | r = &dev->resource[PCI_ROM_RESOURCE]; | ||
221 | r->end -= r->start; | ||
222 | r->start = 0; | ||
223 | if (r->end) | ||
224 | pci_assign_resource(dev, PCI_ROM_RESOURCE); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | |||
229 | void __init pcibios_resource_survey(void) | ||
230 | { | ||
231 | DBG("PCI: Allocating resources\n"); | ||
232 | pcibios_allocate_bus_resources(&pci_root_buses); | ||
233 | pcibios_allocate_resources(0); | ||
234 | pcibios_allocate_resources(1); | ||
235 | pcibios_assign_resources(); | ||
236 | } | ||
237 | |||
238 | int pcibios_enable_resources(struct pci_dev *dev, int mask) | ||
239 | { | ||
240 | u16 cmd, old_cmd; | ||
241 | int idx; | ||
242 | struct resource *r; | ||
243 | |||
244 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
245 | old_cmd = cmd; | ||
246 | for(idx=0; idx<6; idx++) { | ||
247 | /* Only set up the requested stuff */ | ||
248 | if (!(mask & (1<<idx))) | ||
249 | continue; | ||
250 | |||
251 | r = &dev->resource[idx]; | ||
252 | if (!r->start && r->end) { | ||
253 | printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev)); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | if (r->flags & IORESOURCE_IO) | ||
257 | cmd |= PCI_COMMAND_IO; | ||
258 | if (r->flags & IORESOURCE_MEM) | ||
259 | cmd |= PCI_COMMAND_MEMORY; | ||
260 | } | ||
261 | if (dev->resource[PCI_ROM_RESOURCE].start) | ||
262 | cmd |= PCI_COMMAND_MEMORY; | ||
263 | if (cmd != old_cmd) { | ||
264 | printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); | ||
265 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
266 | } | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * If we set up a device for bus mastering, we need to check the latency | ||
272 | * timer as certain crappy BIOSes forget to set it properly. | ||
273 | */ | ||
274 | unsigned int pcibios_max_latency = 255; | ||
275 | |||
276 | void pcibios_set_master(struct pci_dev *dev) | ||
277 | { | ||
278 | u8 lat; | ||
279 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); | ||
280 | if (lat < 16) | ||
281 | lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; | ||
282 | else if (lat > pcibios_max_latency) | ||
283 | lat = pcibios_max_latency; | ||
284 | else | ||
285 | return; | ||
286 | printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); | ||
287 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
288 | } | ||
diff --git a/arch/frv/mb93090-mb00/pci-frv.h b/arch/frv/mb93090-mb00/pci-frv.h new file mode 100644 index 000000000000..7481797ab382 --- /dev/null +++ b/arch/frv/mb93090-mb00/pci-frv.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Low-Level PCI Access for FRV machines. | ||
3 | * | ||
4 | * (c) 1999 Martin Mares <mj@ucw.cz> | ||
5 | */ | ||
6 | |||
7 | #include <asm/sections.h> | ||
8 | |||
9 | #undef DEBUG | ||
10 | |||
11 | #ifdef DEBUG | ||
12 | #define DBG(x...) printk(x) | ||
13 | #else | ||
14 | #define DBG(x...) | ||
15 | #endif | ||
16 | |||
17 | #define PCI_PROBE_BIOS 0x0001 | ||
18 | #define PCI_PROBE_CONF1 0x0002 | ||
19 | #define PCI_PROBE_CONF2 0x0004 | ||
20 | #define PCI_NO_SORT 0x0100 | ||
21 | #define PCI_BIOS_SORT 0x0200 | ||
22 | #define PCI_NO_CHECKS 0x0400 | ||
23 | #define PCI_ASSIGN_ROMS 0x1000 | ||
24 | #define PCI_BIOS_IRQ_SCAN 0x2000 | ||
25 | #define PCI_ASSIGN_ALL_BUSSES 0x4000 | ||
26 | |||
27 | extern unsigned int __nongpreldata pci_probe; | ||
28 | |||
29 | /* pci-frv.c */ | ||
30 | |||
31 | extern unsigned int pcibios_max_latency; | ||
32 | |||
33 | void pcibios_resource_survey(void); | ||
34 | int pcibios_enable_resources(struct pci_dev *, int); | ||
35 | |||
36 | /* pci-vdk.c */ | ||
37 | |||
38 | extern int __nongpreldata pcibios_last_bus; | ||
39 | extern struct pci_bus *__nongpreldata pci_root_bus; | ||
40 | extern struct pci_ops *__nongpreldata pci_root_ops; | ||
41 | |||
42 | /* pci-irq.c */ | ||
43 | extern unsigned int pcibios_irq_mask; | ||
44 | |||
45 | void pcibios_irq_init(void); | ||
46 | void pcibios_fixup_irqs(void); | ||
47 | void pcibios_enable_irq(struct pci_dev *dev); | ||
diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c new file mode 100644 index 000000000000..24622d89b1ca --- /dev/null +++ b/arch/frv/mb93090-mb00/pci-irq.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /* pci-irq.c: PCI IRQ routing on the FRV motherboard | ||
2 | * | ||
3 | * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * derived from: arch/i386/kernel/pci-irq.c: (c) 1999--2000 Martin Mares <mj@suse.cz> | ||
6 | */ | ||
7 | |||
8 | #include <linux/config.h> | ||
9 | #include <linux/types.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/pci.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/irq.h> | ||
16 | |||
17 | #include <asm/io.h> | ||
18 | #include <asm/smp.h> | ||
19 | #include <asm/irq-routing.h> | ||
20 | |||
21 | #include "pci-frv.h" | ||
22 | |||
23 | /* | ||
24 | * DEVICE DEVNO INT#A INT#B INT#C INT#D | ||
25 | * ======= ======= ======= ======= ======= ======= | ||
26 | * MB86943 0 fpga.10 - - - | ||
27 | * RTL8029 16 fpga.12 - - - | ||
28 | * SLOT 1 19 fpga.6 fpga.5 fpga.4 fpga.3 | ||
29 | * SLOT 2 18 fpga.5 fpga.4 fpga.3 fpga.6 | ||
30 | * SLOT 3 17 fpga.4 fpga.3 fpga.6 fpga.5 | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | static const uint8_t __initdata pci_bus0_irq_routing[32][4] = { | ||
35 | [0 ] { IRQ_FPGA_MB86943_PCI_INTA }, | ||
36 | [16] { IRQ_FPGA_RTL8029_INTA }, | ||
37 | [17] { IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB }, | ||
38 | [18] { IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD, IRQ_FPGA_PCI_INTA }, | ||
39 | [19] { IRQ_FPGA_PCI_INTA, IRQ_FPGA_PCI_INTB, IRQ_FPGA_PCI_INTC, IRQ_FPGA_PCI_INTD }, | ||
40 | }; | ||
41 | |||
42 | void __init pcibios_irq_init(void) | ||
43 | { | ||
44 | } | ||
45 | |||
46 | void __init pcibios_fixup_irqs(void) | ||
47 | { | ||
48 | struct pci_dev *dev = NULL; | ||
49 | uint8_t line, pin; | ||
50 | |||
51 | while (dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev), | ||
52 | dev != NULL | ||
53 | ) { | ||
54 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); | ||
55 | if (pin) { | ||
56 | dev->irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1]; | ||
57 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | ||
58 | } | ||
59 | pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | void __init pcibios_penalize_isa_irq(int irq) | ||
64 | { | ||
65 | } | ||
66 | |||
67 | void pcibios_enable_irq(struct pci_dev *dev) | ||
68 | { | ||
69 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | ||
70 | } | ||
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c new file mode 100644 index 000000000000..c8817f7b8605 --- /dev/null +++ b/arch/frv/mb93090-mb00/pci-vdk.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* pci-vdk.c: MB93090-MB00 (VDK) PCI support | ||
2 | * | ||
3 | * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <asm/segment.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <asm/mb-regs.h> | ||
25 | #include <asm/mb86943a.h> | ||
26 | #include "pci-frv.h" | ||
27 | |||
28 | unsigned int __nongpreldata pci_probe = 1; | ||
29 | |||
30 | int __nongpreldata pcibios_last_bus = -1; | ||
31 | struct pci_bus *__nongpreldata pci_root_bus; | ||
32 | struct pci_ops *__nongpreldata pci_root_ops; | ||
33 | |||
34 | /* | ||
35 | * Functions for accessing PCI configuration space | ||
36 | */ | ||
37 | |||
38 | #define CONFIG_CMD(bus, dev, where) \ | ||
39 | (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3)) | ||
40 | |||
41 | #define __set_PciCfgAddr(A) writel((A), (volatile void __iomem *) __region_CS1 + 0x80) | ||
42 | |||
43 | #define __get_PciCfgDataB(A) readb((volatile void __iomem *) __region_CS1 + 0x88 + ((A) & 3)) | ||
44 | #define __get_PciCfgDataW(A) readw((volatile void __iomem *) __region_CS1 + 0x88 + ((A) & 2)) | ||
45 | #define __get_PciCfgDataL(A) readl((volatile void __iomem *) __region_CS1 + 0x88) | ||
46 | |||
47 | #define __set_PciCfgDataB(A,V) \ | ||
48 | writeb((V), (volatile void __iomem *) __region_CS1 + 0x88 + (3 - ((A) & 3))) | ||
49 | |||
50 | #define __set_PciCfgDataW(A,V) \ | ||
51 | writew((V), (volatile void __iomem *) __region_CS1 + 0x88 + (2 - ((A) & 2))) | ||
52 | |||
53 | #define __set_PciCfgDataL(A,V) \ | ||
54 | writel((V), (volatile void __iomem *) __region_CS1 + 0x88) | ||
55 | |||
56 | #define __get_PciBridgeDataB(A) readb((volatile void __iomem *) __region_CS1 + 0x800 + (A)) | ||
57 | #define __get_PciBridgeDataW(A) readw((volatile void __iomem *) __region_CS1 + 0x800 + (A)) | ||
58 | #define __get_PciBridgeDataL(A) readl((volatile void __iomem *) __region_CS1 + 0x800 + (A)) | ||
59 | |||
60 | #define __set_PciBridgeDataB(A,V) writeb((V), (volatile void __iomem *) __region_CS1 + 0x800 + (A)) | ||
61 | #define __set_PciBridgeDataW(A,V) writew((V), (volatile void __iomem *) __region_CS1 + 0x800 + (A)) | ||
62 | #define __set_PciBridgeDataL(A,V) writel((V), (volatile void __iomem *) __region_CS1 + 0x800 + (A)) | ||
63 | |||
64 | static inline int __query(const struct pci_dev *dev) | ||
65 | { | ||
66 | // return dev->bus->number==0 && (dev->devfn==PCI_DEVFN(0,0)); | ||
67 | // return dev->bus->number==1; | ||
68 | // return dev->bus->number==0 && | ||
69 | // (dev->devfn==PCI_DEVFN(2,0) || dev->devfn==PCI_DEVFN(3,0)); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | /*****************************************************************************/ | ||
74 | /* | ||
75 | * | ||
76 | */ | ||
77 | static int pci_frv_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, | ||
78 | u32 *val) | ||
79 | { | ||
80 | u32 _value; | ||
81 | |||
82 | if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) { | ||
83 | _value = __get_PciBridgeDataL(where & ~3); | ||
84 | } | ||
85 | else { | ||
86 | __set_PciCfgAddr(CONFIG_CMD(bus, devfn, where)); | ||
87 | _value = __get_PciCfgDataL(where & ~3); | ||
88 | } | ||
89 | |||
90 | switch (size) { | ||
91 | case 1: | ||
92 | _value = _value >> ((where & 3) * 8); | ||
93 | break; | ||
94 | |||
95 | case 2: | ||
96 | _value = _value >> ((where & 2) * 8); | ||
97 | break; | ||
98 | |||
99 | case 4: | ||
100 | break; | ||
101 | |||
102 | default: | ||
103 | BUG(); | ||
104 | } | ||
105 | |||
106 | *val = _value; | ||
107 | return PCIBIOS_SUCCESSFUL; | ||
108 | } | ||
109 | |||
110 | static int pci_frv_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, | ||
111 | u32 value) | ||
112 | { | ||
113 | switch (size) { | ||
114 | case 1: | ||
115 | if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) { | ||
116 | __set_PciBridgeDataB(where, value); | ||
117 | } | ||
118 | else { | ||
119 | __set_PciCfgAddr(CONFIG_CMD(bus, devfn, where)); | ||
120 | __set_PciCfgDataB(where, value); | ||
121 | } | ||
122 | break; | ||
123 | |||
124 | case 2: | ||
125 | if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) { | ||
126 | __set_PciBridgeDataW(where, value); | ||
127 | } | ||
128 | else { | ||
129 | __set_PciCfgAddr(CONFIG_CMD(bus, devfn, where)); | ||
130 | __set_PciCfgDataW(where, value); | ||
131 | } | ||
132 | break; | ||
133 | |||
134 | case 4: | ||
135 | if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) { | ||
136 | __set_PciBridgeDataL(where, value); | ||
137 | } | ||
138 | else { | ||
139 | __set_PciCfgAddr(CONFIG_CMD(bus, devfn, where)); | ||
140 | __set_PciCfgDataL(where, value); | ||
141 | } | ||
142 | break; | ||
143 | |||
144 | default: | ||
145 | BUG(); | ||
146 | } | ||
147 | |||
148 | return PCIBIOS_SUCCESSFUL; | ||
149 | } | ||
150 | |||
151 | static struct pci_ops pci_direct_frv = { | ||
152 | pci_frv_read_config, | ||
153 | pci_frv_write_config, | ||
154 | }; | ||
155 | |||
156 | /* | ||
157 | * Before we decide to use direct hardware access mechanisms, we try to do some | ||
158 | * trivial checks to ensure it at least _seems_ to be working -- we just test | ||
159 | * whether bus 00 contains a host bridge (this is similar to checking | ||
160 | * techniques used in XFree86, but ours should be more reliable since we | ||
161 | * attempt to make use of direct access hints provided by the PCI BIOS). | ||
162 | * | ||
163 | * This should be close to trivial, but it isn't, because there are buggy | ||
164 | * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. | ||
165 | */ | ||
166 | static int __init pci_sanity_check(struct pci_ops *o) | ||
167 | { | ||
168 | struct pci_bus bus; /* Fake bus and device */ | ||
169 | u32 id; | ||
170 | |||
171 | bus.number = 0; | ||
172 | |||
173 | if (o->read(&bus, 0, PCI_VENDOR_ID, 4, &id) == PCIBIOS_SUCCESSFUL) { | ||
174 | printk("PCI: VDK Bridge device:vendor: %08x\n", id); | ||
175 | if (id == 0x200e10cf) | ||
176 | return 1; | ||
177 | } | ||
178 | |||
179 | printk("PCI: VDK Bridge: Sanity check failed\n"); | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static struct pci_ops * __init pci_check_direct(void) | ||
184 | { | ||
185 | unsigned long flags; | ||
186 | |||
187 | local_irq_save(flags); | ||
188 | |||
189 | /* check if access works */ | ||
190 | if (pci_sanity_check(&pci_direct_frv)) { | ||
191 | local_irq_restore(flags); | ||
192 | printk("PCI: Using configuration frv\n"); | ||
193 | // request_mem_region(0xBE040000, 256, "FRV bridge"); | ||
194 | // request_mem_region(0xBFFFFFF4, 12, "PCI frv"); | ||
195 | return &pci_direct_frv; | ||
196 | } | ||
197 | |||
198 | local_irq_restore(flags); | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Several buggy motherboards address only 16 devices and mirror | ||
204 | * them to next 16 IDs. We try to detect this `feature' on all | ||
205 | * primary buses (those containing host bridges as they are | ||
206 | * expected to be unique) and remove the ghost devices. | ||
207 | */ | ||
208 | |||
209 | static void __init pcibios_fixup_ghosts(struct pci_bus *b) | ||
210 | { | ||
211 | struct list_head *ln, *mn; | ||
212 | struct pci_dev *d, *e; | ||
213 | int mirror = PCI_DEVFN(16,0); | ||
214 | int seen_host_bridge = 0; | ||
215 | int i; | ||
216 | |||
217 | for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { | ||
218 | d = pci_dev_b(ln); | ||
219 | if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) | ||
220 | seen_host_bridge++; | ||
221 | for (mn=ln->next; mn != &b->devices; mn=mn->next) { | ||
222 | e = pci_dev_b(mn); | ||
223 | if (e->devfn != d->devfn + mirror || | ||
224 | e->vendor != d->vendor || | ||
225 | e->device != d->device || | ||
226 | e->class != d->class) | ||
227 | continue; | ||
228 | for(i=0; i<PCI_NUM_RESOURCES; i++) | ||
229 | if (e->resource[i].start != d->resource[i].start || | ||
230 | e->resource[i].end != d->resource[i].end || | ||
231 | e->resource[i].flags != d->resource[i].flags) | ||
232 | continue; | ||
233 | break; | ||
234 | } | ||
235 | if (mn == &b->devices) | ||
236 | return; | ||
237 | } | ||
238 | if (!seen_host_bridge) | ||
239 | return; | ||
240 | printk("PCI: Ignoring ghost devices on bus %02x\n", b->number); | ||
241 | |||
242 | ln = &b->devices; | ||
243 | while (ln->next != &b->devices) { | ||
244 | d = pci_dev_b(ln->next); | ||
245 | if (d->devfn >= mirror) { | ||
246 | list_del(&d->global_list); | ||
247 | list_del(&d->bus_list); | ||
248 | kfree(d); | ||
249 | } else | ||
250 | ln = ln->next; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Discover remaining PCI buses in case there are peer host bridges. | ||
256 | * We use the number of last PCI bus provided by the PCI BIOS. | ||
257 | */ | ||
258 | static void __init pcibios_fixup_peer_bridges(void) | ||
259 | { | ||
260 | struct pci_bus bus; | ||
261 | struct pci_dev dev; | ||
262 | int n; | ||
263 | u16 l; | ||
264 | |||
265 | if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff) | ||
266 | return; | ||
267 | printk("PCI: Peer bridge fixup\n"); | ||
268 | for (n=0; n <= pcibios_last_bus; n++) { | ||
269 | if (pci_find_bus(0, n)) | ||
270 | continue; | ||
271 | bus.number = n; | ||
272 | bus.ops = pci_root_ops; | ||
273 | dev.bus = &bus; | ||
274 | for(dev.devfn=0; dev.devfn<256; dev.devfn += 8) | ||
275 | if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) && | ||
276 | l != 0x0000 && l != 0xffff) { | ||
277 | printk("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l); | ||
278 | printk("PCI: Discovered peer bus %02x\n", n); | ||
279 | pci_scan_bus(n, pci_root_ops, NULL); | ||
280 | break; | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * Exceptions for specific devices. Usually work-arounds for fatal design flaws. | ||
287 | */ | ||
288 | |||
289 | static void __init pci_fixup_umc_ide(struct pci_dev *d) | ||
290 | { | ||
291 | /* | ||
292 | * UM8886BF IDE controller sets region type bits incorrectly, | ||
293 | * therefore they look like memory despite of them being I/O. | ||
294 | */ | ||
295 | int i; | ||
296 | |||
297 | printk("PCI: Fixing base address flags for device %s\n", pci_name(d)); | ||
298 | for(i=0; i<4; i++) | ||
299 | d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; | ||
300 | } | ||
301 | |||
302 | static void __init pci_fixup_ide_bases(struct pci_dev *d) | ||
303 | { | ||
304 | int i; | ||
305 | |||
306 | /* | ||
307 | * PCI IDE controllers use non-standard I/O port decoding, respect it. | ||
308 | */ | ||
309 | if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE) | ||
310 | return; | ||
311 | printk("PCI: IDE base address fixup for %s\n", pci_name(d)); | ||
312 | for(i=0; i<4; i++) { | ||
313 | struct resource *r = &d->resource[i]; | ||
314 | if ((r->start & ~0x80) == 0x374) { | ||
315 | r->start |= 2; | ||
316 | r->end = r->start; | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | static void __init pci_fixup_ide_trash(struct pci_dev *d) | ||
322 | { | ||
323 | int i; | ||
324 | |||
325 | /* | ||
326 | * There exist PCI IDE controllers which have utter garbage | ||
327 | * in first four base registers. Ignore that. | ||
328 | */ | ||
329 | printk("PCI: IDE base address trash cleared for %s\n", pci_name(d)); | ||
330 | for(i=0; i<4; i++) | ||
331 | d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; | ||
332 | } | ||
333 | |||
334 | static void __devinit pci_fixup_latency(struct pci_dev *d) | ||
335 | { | ||
336 | /* | ||
337 | * SiS 5597 and 5598 chipsets require latency timer set to | ||
338 | * at most 32 to avoid lockups. | ||
339 | */ | ||
340 | DBG("PCI: Setting max latency to 32\n"); | ||
341 | pcibios_max_latency = 32; | ||
342 | } | ||
343 | |||
344 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); | ||
345 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_fixup_ide_trash); | ||
346 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); | ||
347 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency); | ||
348 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); | ||
349 | |||
350 | /* | ||
351 | * Called after each bus is probed, but before its children | ||
352 | * are examined. | ||
353 | */ | ||
354 | |||
355 | void __init pcibios_fixup_bus(struct pci_bus *bus) | ||
356 | { | ||
357 | #if 0 | ||
358 | printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number); | ||
359 | #endif | ||
360 | pcibios_fixup_ghosts(bus); | ||
361 | pci_read_bridge_bases(bus); | ||
362 | |||
363 | if (bus->number == 0) { | ||
364 | struct list_head *ln; | ||
365 | struct pci_dev *dev; | ||
366 | for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { | ||
367 | dev = pci_dev_b(ln); | ||
368 | if (dev->devfn == 0) { | ||
369 | dev->resource[0].start = 0; | ||
370 | dev->resource[0].end = 0; | ||
371 | } | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * Initialization. Try all known PCI access methods. Note that we support | ||
378 | * using both PCI BIOS and direct access: in such cases, we use I/O ports | ||
379 | * to access config space, but we still keep BIOS order of cards to be | ||
380 | * compatible with 2.0.X. This should go away some day. | ||
381 | */ | ||
382 | |||
383 | int __init pcibios_init(void) | ||
384 | { | ||
385 | struct pci_ops *dir = NULL; | ||
386 | |||
387 | if (!mb93090_mb00_detected) | ||
388 | return -ENXIO; | ||
389 | |||
390 | __reg_MB86943_sl_ctl |= MB86943_SL_CTL_DRCT_MASTER_SWAP | MB86943_SL_CTL_DRCT_SLAVE_SWAP; | ||
391 | |||
392 | __reg_MB86943_ecs_base(1) = ((__region_CS2 + 0x01000000) >> 9) | 0x08000000; | ||
393 | __reg_MB86943_ecs_base(2) = ((__region_CS2 + 0x00000000) >> 9) | 0x08000000; | ||
394 | |||
395 | *(volatile uint32_t *) (__region_CS1 + 0x848) = 0xe0000000; | ||
396 | *(volatile uint32_t *) (__region_CS1 + 0x8b8) = 0x00000000; | ||
397 | |||
398 | __reg_MB86943_sl_pci_io_base = (__region_CS2 + 0x04000000) >> 9; | ||
399 | __reg_MB86943_sl_pci_mem_base = (__region_CS2 + 0x08000000) >> 9; | ||
400 | __reg_MB86943_pci_sl_io_base = __region_CS2 + 0x04000000; | ||
401 | __reg_MB86943_pci_sl_mem_base = __region_CS2 + 0x08000000; | ||
402 | mb(); | ||
403 | |||
404 | *(volatile unsigned long *)(__region_CS2+0x01300014) == 1; | ||
405 | |||
406 | ioport_resource.start = (__reg_MB86943_sl_pci_io_base << 9) & 0xfffffc00; | ||
407 | ioport_resource.end = (__reg_MB86943_sl_pci_io_range << 9) | 0x3ff; | ||
408 | ioport_resource.end += ioport_resource.start; | ||
409 | |||
410 | printk("PCI IO window: %08lx-%08lx\n", ioport_resource.start, ioport_resource.end); | ||
411 | |||
412 | iomem_resource.start = (__reg_MB86943_sl_pci_mem_base << 9) & 0xfffffc00; | ||
413 | |||
414 | /* Reserve somewhere to write to flush posted writes. */ | ||
415 | iomem_resource.start += 0x400; | ||
416 | |||
417 | iomem_resource.end = (__reg_MB86943_sl_pci_mem_range << 9) | 0x3ff; | ||
418 | iomem_resource.end += iomem_resource.start; | ||
419 | |||
420 | printk("PCI MEM window: %08lx-%08lx\n", iomem_resource.start, iomem_resource.end); | ||
421 | printk("PCI DMA memory: %08lx-%08lx\n", dma_coherent_mem_start, dma_coherent_mem_end); | ||
422 | |||
423 | if (!pci_probe) | ||
424 | return -ENXIO; | ||
425 | |||
426 | dir = pci_check_direct(); | ||
427 | if (dir) | ||
428 | pci_root_ops = dir; | ||
429 | else { | ||
430 | printk("PCI: No PCI bus detected\n"); | ||
431 | return -ENXIO; | ||
432 | } | ||
433 | |||
434 | printk("PCI: Probing PCI hardware\n"); | ||
435 | pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL); | ||
436 | |||
437 | pcibios_irq_init(); | ||
438 | pcibios_fixup_peer_bridges(); | ||
439 | pcibios_fixup_irqs(); | ||
440 | pcibios_resource_survey(); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | arch_initcall(pcibios_init); | ||
446 | |||
447 | char * __init pcibios_setup(char *str) | ||
448 | { | ||
449 | if (!strcmp(str, "off")) { | ||
450 | pci_probe = 0; | ||
451 | return NULL; | ||
452 | } else if (!strncmp(str, "lastbus=", 8)) { | ||
453 | pcibios_last_bus = simple_strtol(str+8, NULL, 0); | ||
454 | return NULL; | ||
455 | } | ||
456 | return str; | ||
457 | } | ||
458 | |||
459 | int pcibios_enable_device(struct pci_dev *dev, int mask) | ||
460 | { | ||
461 | int err; | ||
462 | |||
463 | if ((err = pcibios_enable_resources(dev, mask)) < 0) | ||
464 | return err; | ||
465 | pcibios_enable_irq(dev); | ||
466 | return 0; | ||
467 | } | ||