OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [powerpc/] [kernel/] [isa-bridge.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Routines for tracking a legacy ISA bridge
3
 *
4
 * Copyrigh 2007 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
5
 *
6
 * Some bits and pieces moved over from pci_64.c
7
 *
8
 * Copyrigh 2003 Anton Blanchard <anton@au.ibm.com>, IBM Corp.
9
 *
10
 *      This program is free software; you can redistribute it and/or
11
 *      modify it under the terms of the GNU General Public License
12
 *      as published by the Free Software Foundation; either version
13
 *      2 of the License, or (at your option) any later version.
14
 */
15
 
16
#define DEBUG
17
 
18
#include <linux/kernel.h>
19
#include <linux/pci.h>
20
#include <linux/string.h>
21
#include <linux/init.h>
22
#include <linux/mm.h>
23
#include <linux/notifier.h>
24
 
25
#include <asm/processor.h>
26
#include <asm/io.h>
27
#include <asm/prom.h>
28
#include <asm/pci-bridge.h>
29
#include <asm/machdep.h>
30
#include <asm/ppc-pci.h>
31
#include <asm/firmware.h>
32
 
33
unsigned long isa_io_base;      /* NULL if no ISA bus */
34
EXPORT_SYMBOL(isa_io_base);
35
 
36
/* Cached ISA bridge dev. */
37
static struct device_node *isa_bridge_devnode;
38
struct pci_dev *isa_bridge_pcidev;
39
EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
40
 
41
#define ISA_SPACE_MASK 0x1
42
#define ISA_SPACE_IO 0x1
43
 
44
static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
45
                                                unsigned long phb_io_base_phys)
46
{
47
        /* We should get some saner parsing here and remove these structs */
48
        struct pci_address {
49
                u32 a_hi;
50
                u32 a_mid;
51
                u32 a_lo;
52
        };
53
 
54
        struct isa_address {
55
                u32 a_hi;
56
                u32 a_lo;
57
        };
58
 
59
        struct isa_range {
60
                struct isa_address isa_addr;
61
                struct pci_address pci_addr;
62
                unsigned int size;
63
        };
64
 
65
        const struct isa_range *range;
66
        unsigned long pci_addr;
67
        unsigned int isa_addr;
68
        unsigned int size;
69
        int rlen = 0;
70
 
71
        range = of_get_property(isa_node, "ranges", &rlen);
72
        if (range == NULL || (rlen < sizeof(struct isa_range)))
73
                goto inval_range;
74
 
75
        /* From "ISA Binding to 1275"
76
         * The ranges property is laid out as an array of elements,
77
         * each of which comprises:
78
         *   cells 0 - 1:       an ISA address
79
         *   cells 2 - 4:       a PCI address
80
         *                      (size depending on dev->n_addr_cells)
81
         *   cell 5:            the size of the range
82
         */
83
        if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO) {
84
                range++;
85
                rlen -= sizeof(struct isa_range);
86
                if (rlen < sizeof(struct isa_range))
87
                        goto inval_range;
88
        }
89
        if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO)
90
                goto inval_range;
91
 
92
        isa_addr = range->isa_addr.a_lo;
93
        pci_addr = (unsigned long) range->pci_addr.a_mid << 32 |
94
                range->pci_addr.a_lo;
95
 
96
        /* Assume these are both zero. Note: We could fix that and
97
         * do a proper parsing instead ... oh well, that will do for
98
         * now as nobody uses fancy mappings for ISA bridges
99
         */
100
        if ((pci_addr != 0) || (isa_addr != 0)) {
101
                printk(KERN_ERR "unexpected isa to pci mapping: %s\n",
102
                       __FUNCTION__);
103
                return;
104
        }
105
 
106
        /* Align size and make sure it's cropped to 64K */
107
        size = PAGE_ALIGN(range->size);
108
        if (size > 0x10000)
109
                size = 0x10000;
110
 
111
        printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
112
               "mapping 64k\n");
113
 
114
        __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
115
                     size, _PAGE_NO_CACHE|_PAGE_GUARDED);
116
        return;
117
 
118
inval_range:
119
        printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
120
               "mapping 64k\n");
121
        __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
122
                     0x10000, _PAGE_NO_CACHE|_PAGE_GUARDED);
123
}
124
 
125
 
126
/**
127
 * isa_bridge_find_early - Find and map the ISA IO space early before
128
 *                         main PCI discovery. This is optionally called by
129
 *                         the arch code when adding PCI PHBs to get early
130
 *                         access to ISA IO ports
131
 */
132
void __init isa_bridge_find_early(struct pci_controller *hose)
133
{
134
        struct device_node *np, *parent = NULL, *tmp;
135
 
136
        /* If we already have an ISA bridge, bail off */
137
        if (isa_bridge_devnode != NULL)
138
                return;
139
 
140
        /* For each "isa" node in the system. Note : we do a search by
141
         * type and not by name. It might be better to do by name but that's
142
         * what the code used to do and I don't want to break too much at
143
         * once. We can look into changing that separately
144
         */
145
        for_each_node_by_type(np, "isa") {
146
                /* Look for our hose being a parent */
147
                for (parent = of_get_parent(np); parent;) {
148
                        if (parent == hose->arch_data) {
149
                                of_node_put(parent);
150
                                break;
151
                        }
152
                        tmp = parent;
153
                        parent = of_get_parent(parent);
154
                        of_node_put(tmp);
155
                }
156
                if (parent != NULL)
157
                        break;
158
        }
159
        if (np == NULL)
160
                return;
161
        isa_bridge_devnode = np;
162
 
163
        /* Now parse the "ranges" property and setup the ISA mapping */
164
        pci_process_ISA_OF_ranges(np, hose->io_base_phys);
165
 
166
        /* Set the global ISA io base to indicate we have an ISA bridge */
167
        isa_io_base = ISA_IO_BASE;
168
 
169
        pr_debug("ISA bridge (early) is %s\n", np->full_name);
170
}
171
 
172
/**
173
 * isa_bridge_find_late - Find and map the ISA IO space upon discovery of
174
 *                        a new ISA bridge
175
 */
176
static void __devinit isa_bridge_find_late(struct pci_dev *pdev,
177
                                           struct device_node *devnode)
178
{
179
        struct pci_controller *hose = pci_bus_to_host(pdev->bus);
180
 
181
        /* Store ISA device node and PCI device */
182
        isa_bridge_devnode = of_node_get(devnode);
183
        isa_bridge_pcidev = pdev;
184
 
185
        /* Now parse the "ranges" property and setup the ISA mapping */
186
        pci_process_ISA_OF_ranges(devnode, hose->io_base_phys);
187
 
188
        /* Set the global ISA io base to indicate we have an ISA bridge */
189
        isa_io_base = ISA_IO_BASE;
190
 
191
        pr_debug("ISA bridge (late) is %s on %s\n",
192
                 devnode->full_name, pci_name(pdev));
193
}
194
 
195
/**
196
 * isa_bridge_remove - Remove/unmap an ISA bridge
197
 */
198
static void isa_bridge_remove(void)
199
{
200
        pr_debug("ISA bridge removed !\n");
201
 
202
        /* Clear the global ISA io base to indicate that we have no more
203
         * ISA bridge. Note that drivers don't quite handle that, though
204
         * we should probably do something about it. But do we ever really
205
         * have ISA bridges being removed on machines using legacy devices ?
206
         */
207
        isa_io_base = ISA_IO_BASE;
208
 
209
        /* Clear references to the bridge */
210
        of_node_put(isa_bridge_devnode);
211
        isa_bridge_devnode = NULL;
212
        isa_bridge_pcidev = NULL;
213
 
214
        /* Unmap the ISA area */
215
        __iounmap_at((void *)ISA_IO_BASE, 0x10000);
216
}
217
 
218
/**
219
 * isa_bridge_notify - Get notified of PCI devices addition/removal
220
 */
221
static int __devinit isa_bridge_notify(struct notifier_block *nb,
222
                                       unsigned long action, void *data)
223
{
224
        struct device *dev = data;
225
        struct pci_dev *pdev = to_pci_dev(dev);
226
        struct device_node *devnode = pci_device_to_OF_node(pdev);
227
 
228
        switch(action) {
229
        case BUS_NOTIFY_ADD_DEVICE:
230
                /* Check if we have an early ISA device, without PCI dev */
231
                if (isa_bridge_devnode && isa_bridge_devnode == devnode &&
232
                    !isa_bridge_pcidev) {
233
                        pr_debug("ISA bridge PCI attached: %s\n",
234
                                 pci_name(pdev));
235
                        isa_bridge_pcidev = pdev;
236
                }
237
 
238
                /* Check if we have no ISA device, and this happens to be one,
239
                 * register it as such if it has an OF device
240
                 */
241
                if (!isa_bridge_devnode && devnode && devnode->type &&
242
                    !strcmp(devnode->type, "isa"))
243
                        isa_bridge_find_late(pdev, devnode);
244
 
245
                return 0;
246
        case BUS_NOTIFY_DEL_DEVICE:
247
                /* Check if this our existing ISA device */
248
                if (pdev == isa_bridge_pcidev ||
249
                    (devnode && devnode == isa_bridge_devnode))
250
                        isa_bridge_remove();
251
                return 0;
252
        }
253
        return 0;
254
}
255
 
256
static struct notifier_block isa_bridge_notifier = {
257
        .notifier_call = isa_bridge_notify
258
};
259
 
260
/**
261
 * isa_bridge_init - register to be notified of ISA bridge addition/removal
262
 *
263
 */
264
static int __init isa_bridge_init(void)
265
{
266
        if (firmware_has_feature(FW_FEATURE_ISERIES))
267
                return 0;
268
        bus_register_notifier(&pci_bus_type, &isa_bridge_notifier);
269
        return 0;
270
}
271
arch_initcall(isa_bridge_init);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.