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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [mtd/] [maps/] [scb2_flash.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * MTD map driver for BIOS Flash on Intel SCB2 boards
3
 * $Id: scb2_flash.c,v 1.1.1.1 2004-04-15 01:51:51 phoenix Exp $
4
 * Copyright (C) 2002 Sun Microsystems, Inc.
5
 * Tim Hockin <thockin@sun.com>
6
 *
7
 * A few notes on this MTD map:
8
 *
9
 * This was developed with a small number of SCB2 boards to test on.
10
 * Hopefully, Intel has not introducted too many unaccounted variables in the
11
 * making of this board.
12
 *
13
 * The BIOS marks its own memory region as 'reserved' in the e820 map.  We
14
 * try to request it here, but if it fails, we carry on anyway.
15
 *
16
 * This is how the chip is attached, so said the schematic:
17
 * * a 4 MiB (32 Mb) 16 bit chip
18
 * * a 1 MiB memory region
19
 * * A20 and A21 pulled up
20
 * * D8-D15 ignored
21
 * What this means is that, while we are addressing bytes linearly, we are
22
 * really addressing words, and discarding the other byte.  This means that
23
 * the chip MUST BE at least 2 MiB.  This also means that every block is
24
 * actually half as big as the chip reports.  It also means that accesses of
25
 * logical address 0 hit higher-address sections of the chip, not physical 0.
26
 * One can only hope that these 4MiB x16 chips were a lot cheaper than 1MiB x8
27
 * chips.
28
 *
29
 * This driver assumes the chip is not write-protected by an external signal.
30
 * As of the this writing, that is true, but may change, just to spite me.
31
 *
32
 * The actual BIOS layout has been mostly reverse engineered.  Intel BIOS
33
 * updates for this board include 10 related (*.bio - &.bi9) binary files and
34
 * another seperate (*.bbo) binary file.  The 10 files are 64k of data + a
35
 * small header.  If the headers are stripped off, the 10 64k files can be
36
 * concatenated into a 640k image.  This is your BIOS image, proper.  The
37
 * seperate .bbo file also has a small header.  It is the 'Boot Block'
38
 * recovery BIOS.  Once the header is stripped, no further prep is needed.
39
 * As best I can tell, the BIOS is arranged as such:
40
 * offset 0x00000 to 0x4ffff (320k):  unknown - SCSI BIOS, etc?
41
 * offset 0x50000 to 0xeffff (640k):  BIOS proper
42
 * offset 0xf0000 ty 0xfffff (64k):   Boot Block region
43
 *
44
 * Intel's BIOS update program flashes the BIOS and Boot Block in seperate
45
 * steps.  Probably a wise thing to do.
46
 */
47
 
48
#include <linux/module.h>
49
#include <linux/types.h>
50
#include <linux/kernel.h>
51
#include <asm/io.h>
52
#include <linux/mtd/mtd.h>
53
#include <linux/mtd/map.h>
54
#include <linux/mtd/cfi.h>
55
#include <linux/config.h>
56
#include <linux/pci.h>
57
#include <linux/pci_ids.h>
58
 
59
#define MODNAME         "scb2_flash"
60
#define SCB2_ADDR       0xfff00000
61
#define SCB2_WINDOW     0x00100000
62
 
63
static __u8 scb2_read8(struct map_info *map, unsigned long ofs)
64
{
65
        return __raw_readb(map->map_priv_1 + ofs);
66
}
67
 
68
static __u16 scb2_read16(struct map_info *map, unsigned long ofs)
69
{
70
        return __raw_readw(map->map_priv_1 + ofs);
71
}
72
 
73
static __u32 scb2_read32(struct map_info *map, unsigned long ofs)
74
{
75
        return __raw_readl(map->map_priv_1 + ofs);
76
}
77
 
78
static void scb2_copy_from(struct map_info *map, void *to,
79
                                 unsigned long from, ssize_t len)
80
{
81
        memcpy_fromio(to, map->map_priv_1 + from, len);
82
}
83
 
84
static void scb2_write8(struct map_info *map, __u8 d, unsigned long adr)
85
{
86
        __raw_writeb(d, map->map_priv_1 + adr);
87
        mb();
88
}
89
 
90
static void scb2_write16(struct map_info *map, __u16 d, unsigned long adr)
91
{
92
        __raw_writew(d, map->map_priv_1 + adr);
93
        mb();
94
}
95
 
96
static void scb2_write32(struct map_info *map, __u32 d, unsigned long adr)
97
{
98
        __raw_writel(d, map->map_priv_1 + adr);
99
        mb();
100
}
101
 
102
static void scb2_copy_to(struct map_info *map, unsigned long to,
103
                               const void *from, ssize_t len)
104
{
105
        memcpy_toio(map->map_priv_1 + to, from, len);
106
}
107
 
108
static void *scb2_ioaddr;
109
static struct mtd_info *scb2_mtd;
110
struct map_info scb2_map = {
111
        name:      "SCB2 BIOS Flash",
112
        size:      0,
113
        buswidth:  1,
114
        read8:     scb2_read8,
115
        read16:    scb2_read16,
116
        read32:    scb2_read32,
117
        copy_from: scb2_copy_from,
118
        write8:    scb2_write8,
119
        write16:   scb2_write16,
120
        write32:   scb2_write32,
121
        copy_to:   scb2_copy_to,
122
};
123
static int region_fail;
124
 
125
static int __devinit
126
scb2_fixup_mtd(struct mtd_info *mtd)
127
{
128
        int i;
129
        int done = 0;
130
        struct map_info *map = mtd->priv;
131
        struct cfi_private *cfi = map->fldrv_priv;
132
 
133
        /* barf if this doesn't look right */
134
        if (cfi->cfiq->InterfaceDesc != 1) {
135
                printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
136
                    cfi->cfiq->InterfaceDesc);
137
                return -1;
138
        }
139
 
140
        /* the chip is sometimes bigger than the map - what a waste */
141
        mtd->size = map->size;
142
 
143
        /*
144
         * We only REALLY get half the chip, due to the way it is
145
         * wired up - D8-D15 are tossed away.  We read linear bytes,
146
         * but in reality we are getting 1/2 of each 16-bit read,
147
         * which LOOKS linear to us.  Because CFI code accounts for
148
         * things like lock/unlock/erase by eraseregions, we need to
149
         * fudge them to reflect this.  Erases go like this:
150
         *   * send an erase to an address
151
         *   * the chip samples the address and erases the block
152
         *   * add the block erasesize to the address and repeat
153
         *   -- the problem is that addresses are 16-bit addressable
154
         *   -- we end up erasing every-other block
155
         */
156
        mtd->erasesize /= 2;
157
        for (i = 0; i < mtd->numeraseregions; i++) {
158
                struct mtd_erase_region_info *region = &mtd->eraseregions[i];
159
                region->erasesize /= 2;
160
        }
161
 
162
        /*
163
         * If the chip is bigger than the map, it is wired with the high
164
         * address lines pulled up.  This makes us access the top portion of
165
         * the chip, so all our erase-region info is wrong.  Start cutting from
166
         * the bottom.
167
         */
168
        for (i = 0; !done && i < mtd->numeraseregions; i++) {
169
                struct mtd_erase_region_info *region = &mtd->eraseregions[i];
170
 
171
                if (region->numblocks * region->erasesize > mtd->size) {
172
                        region->numblocks = (mtd->size / region->erasesize);
173
                        done = 1;
174
                } else {
175
                        region->numblocks = 0;
176
                }
177
                region->offset = 0;
178
        }
179
 
180
        return 0;
181
}
182
 
183
/* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
184
#define CSB5_FCR        0x41
185
#define CSB5_FCR_DECODE_ALL 0x0e
186
static int __devinit
187
scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
188
{
189
        u8 reg;
190
 
191
        /* enable decoding of the flash region in the south bridge */
192
        pci_read_config_byte(dev, CSB5_FCR, &reg);
193
        pci_write_config_byte(dev, CSB5_FCR, reg | CSB5_FCR_DECODE_ALL);
194
 
195
        if (!request_mem_region(SCB2_ADDR, SCB2_WINDOW, scb2_map.name)) {
196
                /*
197
                 * The BIOS seems to mark the flash region as 'reserved'
198
                 * in the e820 map.  Warn and go about our business.
199
                 */
200
                printk(KERN_WARNING MODNAME
201
                    ": warning - can't reserve rom window, continuing\n");
202
                region_fail = 1;
203
        }
204
 
205
        /* remap the IO window (w/o caching) */
206
        scb2_ioaddr = ioremap_nocache(SCB2_ADDR, SCB2_WINDOW);
207
        if (!scb2_ioaddr) {
208
                printk(KERN_ERR MODNAME ": Failed to ioremap window!\n");
209
                if (!region_fail)
210
                        release_mem_region(SCB2_ADDR, SCB2_WINDOW);
211
                return -ENOMEM;
212
        }
213
 
214
        scb2_map.map_priv_1 = (unsigned long)scb2_ioaddr;
215
        scb2_map.size = SCB2_WINDOW;
216
 
217
        /* try to find a chip */
218
        scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
219
 
220
        if (!scb2_mtd) {
221
                printk(KERN_ERR MODNAME ": flash probe failed!\n");
222
                iounmap(scb2_ioaddr);
223
                if (!region_fail)
224
                        release_mem_region(SCB2_ADDR, SCB2_WINDOW);
225
                return -ENODEV;
226
        }
227
 
228
        scb2_mtd->module = THIS_MODULE;
229
        if (scb2_fixup_mtd(scb2_mtd) < 0) {
230
                del_mtd_device(scb2_mtd);
231
                map_destroy(scb2_mtd);
232
                iounmap(scb2_ioaddr);
233
                if (!region_fail)
234
                        release_mem_region(SCB2_ADDR, SCB2_WINDOW);
235
                return -ENODEV;
236
        }
237
 
238
        printk(KERN_NOTICE MODNAME ": chip size %x at offset %x\n",
239
               scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
240
 
241
        add_mtd_device(scb2_mtd);
242
 
243
        return 0;
244
}
245
 
246
static void __devexit
247
scb2_flash_remove(struct pci_dev *dev)
248
{
249
        if (!scb2_mtd)
250
                return;
251
 
252
        /* disable flash writes */
253
        if (scb2_mtd->lock)
254
                scb2_mtd->lock(scb2_mtd, 0, scb2_mtd->size);
255
 
256
        del_mtd_device(scb2_mtd);
257
        map_destroy(scb2_mtd);
258
 
259
        iounmap(scb2_ioaddr);
260
        scb2_ioaddr = NULL;
261
 
262
        if (!region_fail)
263
                release_mem_region(SCB2_ADDR, SCB2_WINDOW);
264
        pci_set_drvdata(dev, NULL);
265
}
266
 
267
static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = {
268
        {
269
          vendor: PCI_VENDOR_ID_SERVERWORKS,
270
          device: PCI_DEVICE_ID_SERVERWORKS_CSB5,
271
          subvendor: PCI_ANY_ID,
272
          subdevice: PCI_ANY_ID
273
        },
274
        { 0, }
275
};
276
 
277
static struct pci_driver scb2_flash_driver = {
278
        name:     "Intel SCB2 BIOS Flash",
279
        id_table: scb2_flash_pci_ids,
280
        probe:    scb2_flash_probe,
281
        remove:   __devexit_p(scb2_flash_remove),
282
};
283
 
284
static int __init
285
scb2_flash_init(void)
286
{
287
        return pci_module_init(&scb2_flash_driver);
288
}
289
 
290
static void __exit
291
scb2_flash_exit(void)
292
{
293
        pci_unregister_driver(&scb2_flash_driver);
294
}
295
 
296
module_init(scb2_flash_init);
297
module_exit(scb2_flash_exit);
298
 
299
MODULE_LICENSE("GPL");
300
MODULE_AUTHOR("Tim Hockin <thockin@sun.com>");
301
MODULE_DESCRIPTION("MTD map driver for Intel SCB2 BIOS Flash");
302
MODULE_DEVICE_TABLE(pci, scb2_flash_pci_ids);

powered by: WebSVN 2.1.0

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