~ubuntu-branches/ubuntu/edgy/mtd/edgy

« back to all changes in this revision

Viewing changes to drivers/mtd/maps/scb2_flash.c

  • Committer: Bazaar Package Importer
  • Author(s): Riku Voipio
  • Date: 2005-01-23 12:56:16 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050123125616-jlum1hlbtsj2sx5f
Tags: 20050122-2
* Fix the version, darn
* Get rid of historic conflict, closes: #160614

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * MTD map driver for BIOS Flash on Intel SCB2 boards
 
3
 * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 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 Mib) 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 separate (*.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
 * separate .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 separate
 
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 <linux/init.h>
 
52
#include <asm/io.h>
 
53
#include <linux/mtd/mtd.h>
 
54
#include <linux/mtd/map.h>
 
55
#include <linux/mtd/cfi.h>
 
56
#include <linux/config.h>
 
57
#include <linux/pci.h>
 
58
#include <linux/pci_ids.h>
 
59
 
 
60
#define MODNAME         "scb2_flash"
 
61
#define SCB2_ADDR       0xfff00000
 
62
#define SCB2_WINDOW     0x00100000
 
63
 
 
64
 
 
65
static void __iomem *scb2_ioaddr;
 
66
static struct mtd_info *scb2_mtd;
 
67
static struct map_info scb2_map = {
 
68
        .name =      "SCB2 BIOS Flash",
 
69
        .size =      0,
 
70
        .bankwidth =  1,
 
71
};
 
72
static int region_fail;
 
73
 
 
74
static int __devinit
 
75
scb2_fixup_mtd(struct mtd_info *mtd)
 
76
{
 
77
        int i;
 
78
        int done = 0;
 
79
        struct map_info *map = mtd->priv;
 
80
        struct cfi_private *cfi = map->fldrv_priv;
 
81
 
 
82
        /* barf if this doesn't look right */
 
83
        if (cfi->cfiq->InterfaceDesc != 1) {
 
84
                printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
 
85
                    cfi->cfiq->InterfaceDesc);
 
86
                return -1;
 
87
        }
 
88
 
 
89
        /* I wasn't here. I didn't see. dwmw2. */
 
90
 
 
91
        /* the chip is sometimes bigger than the map - what a waste */
 
92
        mtd->size = map->size;
 
93
 
 
94
        /*
 
95
         * We only REALLY get half the chip, due to the way it is
 
96
         * wired up - D8-D15 are tossed away.  We read linear bytes,
 
97
         * but in reality we are getting 1/2 of each 16-bit read,
 
98
         * which LOOKS linear to us.  Because CFI code accounts for
 
99
         * things like lock/unlock/erase by eraseregions, we need to
 
100
         * fudge them to reflect this.  Erases go like this:
 
101
         *   * send an erase to an address
 
102
         *   * the chip samples the address and erases the block
 
103
         *   * add the block erasesize to the address and repeat
 
104
         *   -- the problem is that addresses are 16-bit addressable
 
105
         *   -- we end up erasing every-other block
 
106
         */
 
107
        mtd->erasesize /= 2;
 
108
        for (i = 0; i < mtd->numeraseregions; i++) {
 
109
                struct mtd_erase_region_info *region = &mtd->eraseregions[i];
 
110
                region->erasesize /= 2;
 
111
        }
 
112
 
 
113
        /*
 
114
         * If the chip is bigger than the map, it is wired with the high
 
115
         * address lines pulled up.  This makes us access the top portion of
 
116
         * the chip, so all our erase-region info is wrong.  Start cutting from
 
117
         * the bottom.
 
118
         */
 
119
        for (i = 0; !done && i < mtd->numeraseregions; i++) {
 
120
                struct mtd_erase_region_info *region = &mtd->eraseregions[i];
 
121
 
 
122
                if (region->numblocks * region->erasesize > mtd->size) {
 
123
                        region->numblocks = (mtd->size / region->erasesize);
 
124
                        done = 1;
 
125
                } else {
 
126
                        region->numblocks = 0;
 
127
                }
 
128
                region->offset = 0;
 
129
        }
 
130
 
 
131
        return 0;
 
132
}
 
133
 
 
134
/* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
 
135
#define CSB5_FCR        0x41
 
136
#define CSB5_FCR_DECODE_ALL 0x0e
 
137
static int __devinit
 
138
scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 
139
{
 
140
        u8 reg;
 
141
 
 
142
        /* enable decoding of the flash region in the south bridge */
 
143
        pci_read_config_byte(dev, CSB5_FCR, &reg);
 
144
        pci_write_config_byte(dev, CSB5_FCR, reg | CSB5_FCR_DECODE_ALL);
 
145
 
 
146
        if (!request_mem_region(SCB2_ADDR, SCB2_WINDOW, scb2_map.name)) {
 
147
                /*
 
148
                 * The BIOS seems to mark the flash region as 'reserved'
 
149
                 * in the e820 map.  Warn and go about our business.
 
150
                 */
 
151
                printk(KERN_WARNING MODNAME
 
152
                    ": warning - can't reserve rom window, continuing\n");
 
153
                region_fail = 1;
 
154
        }
 
155
 
 
156
        /* remap the IO window (w/o caching) */
 
157
        scb2_ioaddr = ioremap_nocache(SCB2_ADDR, SCB2_WINDOW);
 
158
        if (!scb2_ioaddr) {
 
159
                printk(KERN_ERR MODNAME ": Failed to ioremap window!\n");
 
160
                if (!region_fail)
 
161
                        release_mem_region(SCB2_ADDR, SCB2_WINDOW);
 
162
                return -ENOMEM;
 
163
        }
 
164
 
 
165
        scb2_map.phys = SCB2_ADDR;
 
166
        scb2_map.virt = scb2_ioaddr;
 
167
        scb2_map.size = SCB2_WINDOW;
 
168
 
 
169
        simple_map_init(&scb2_map);
 
170
 
 
171
        /* try to find a chip */
 
172
        scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
 
173
 
 
174
        if (!scb2_mtd) {
 
175
                printk(KERN_ERR MODNAME ": flash probe failed!\n");
 
176
                iounmap(scb2_ioaddr);
 
177
                if (!region_fail)
 
178
                        release_mem_region(SCB2_ADDR, SCB2_WINDOW);
 
179
                return -ENODEV;
 
180
        }
 
181
 
 
182
        scb2_mtd->owner = THIS_MODULE;
 
183
        if (scb2_fixup_mtd(scb2_mtd) < 0) {
 
184
                del_mtd_device(scb2_mtd);
 
185
                map_destroy(scb2_mtd);
 
186
                iounmap(scb2_ioaddr);
 
187
                if (!region_fail)
 
188
                        release_mem_region(SCB2_ADDR, SCB2_WINDOW);
 
189
                return -ENODEV;
 
190
        }
 
191
 
 
192
        printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n",
 
193
               scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
 
194
 
 
195
        add_mtd_device(scb2_mtd);
 
196
 
 
197
        return 0;
 
198
}
 
199
 
 
200
static void __devexit
 
201
scb2_flash_remove(struct pci_dev *dev)
 
202
{
 
203
        if (!scb2_mtd)
 
204
                return;
 
205
 
 
206
        /* disable flash writes */
 
207
        if (scb2_mtd->lock)
 
208
                scb2_mtd->lock(scb2_mtd, 0, scb2_mtd->size);
 
209
 
 
210
        del_mtd_device(scb2_mtd);
 
211
        map_destroy(scb2_mtd);
 
212
 
 
213
        iounmap(scb2_ioaddr);
 
214
        scb2_ioaddr = NULL;
 
215
 
 
216
        if (!region_fail)
 
217
                release_mem_region(SCB2_ADDR, SCB2_WINDOW);
 
218
        pci_set_drvdata(dev, NULL);
 
219
}
 
220
 
 
221
static struct pci_device_id scb2_flash_pci_ids[] = {
 
222
        {
 
223
          .vendor = PCI_VENDOR_ID_SERVERWORKS,
 
224
          .device = PCI_DEVICE_ID_SERVERWORKS_CSB5,
 
225
          .subvendor = PCI_ANY_ID,
 
226
          .subdevice = PCI_ANY_ID
 
227
        },
 
228
        { 0, }
 
229
};
 
230
 
 
231
static struct pci_driver scb2_flash_driver = {
 
232
        .name =     "Intel SCB2 BIOS Flash",
 
233
        .id_table = scb2_flash_pci_ids,
 
234
        .probe =    scb2_flash_probe,
 
235
        .remove =   __devexit_p(scb2_flash_remove),
 
236
};
 
237
 
 
238
static int __init
 
239
scb2_flash_init(void)
 
240
{
 
241
        return pci_module_init(&scb2_flash_driver);
 
242
}
 
243
 
 
244
static void __exit
 
245
scb2_flash_exit(void)
 
246
{
 
247
        pci_unregister_driver(&scb2_flash_driver);
 
248
}
 
249
 
 
250
module_init(scb2_flash_init);
 
251
module_exit(scb2_flash_exit);
 
252
 
 
253
MODULE_LICENSE("GPL");
 
254
MODULE_AUTHOR("Tim Hockin <thockin@sun.com>");
 
255
MODULE_DESCRIPTION("MTD map driver for Intel SCB2 BIOS Flash");
 
256
MODULE_DEVICE_TABLE(pci, scb2_flash_pci_ids);