import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / mtd / maps / sc520cdp.c
1 /* sc520cdp.c -- MTD map driver for AMD SC520 Customer Development Platform
2  *
3  * Copyright (C) 2001 Sysgo Real-Time Solutions GmbH
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  *
19  * $Id: sc520cdp.c,v 1.11 2002/03/08 16:34:35 rkaiser Exp $
20  *
21  *
22  * The SC520CDP is an evaluation board for the Elan SC520 processor available
23  * from AMD. It has two banks of 32-bit Flash ROM, each 8 Megabytes in size,
24  * and up to 512 KiB of 8-bit DIL Flash ROM.
25  * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
26  */
27
28 #include <linux/config.h>
29 #include <linux/module.h>
30 #include <linux/types.h>
31 #include <linux/kernel.h>
32 #include <asm/io.h>
33 #include <linux/mtd/mtd.h>
34 #include <linux/mtd/map.h>
35 #include <linux/mtd/concat.h>
36
37 /*
38 ** The Embedded Systems BIOS decodes the first FLASH starting at
39 ** 0x8400000. This is a *terrible* place for it because accessing
40 ** the flash at this location causes the A22 address line to be high
41 ** (that's what 0x8400000 binary's ought to be). But this is the highest
42 ** order address line on the raw flash devices themselves!!
43 ** This causes the top HALF of the flash to be accessed first. Beyond
44 ** the physical limits of the flash, the flash chip aliases over (to
45 ** 0x880000 which causes the bottom half to be accessed. This splits the
46 ** flash into two and inverts it! If you then try to access this from another
47 ** program that does NOT do this insanity, then you *will* access the
48 ** first half of the flash, but not find what you expect there. That
49 ** stuff is in the *second* half! Similarly, the address used by the
50 ** BIOS for the second FLASH bank is also quite a bad choice.
51 ** If REPROGRAM_PAR is defined below (the default), then this driver will
52 ** choose more useful addresses for the FLASH banks by reprogramming the
53 ** responsible PARxx registers in the SC520's MMCR region. This will
54 ** cause the settings to be incompatible with the BIOS's settings, which
55 ** shouldn't be a problem since you are running Linux, (i.e. the BIOS is
56 ** not much use anyway). However, if you need to be compatible with
57 ** the BIOS for some reason, just undefine REPROGRAM_PAR.
58 */
59 #define REPROGRAM_PAR
60
61
62
63 #ifdef REPROGRAM_PAR
64
65 /* These are the addresses we want.. */
66 #define WINDOW_ADDR_0   0x08800000
67 #define WINDOW_ADDR_1   0x09000000
68 #define WINDOW_ADDR_2   0x09800000
69
70 /* .. and these are the addresses the BIOS gives us */
71 #define WINDOW_ADDR_0_BIOS      0x08400000
72 #define WINDOW_ADDR_1_BIOS      0x08c00000
73 #define WINDOW_ADDR_2_BIOS      0x09400000
74
75 #else
76
77 #define WINDOW_ADDR_0   0x08400000
78 #define WINDOW_ADDR_1   0x08C00000
79 #define WINDOW_ADDR_2   0x09400000
80
81 #endif
82
83 #define WINDOW_SIZE_0   0x00800000
84 #define WINDOW_SIZE_1   0x00800000
85 #define WINDOW_SIZE_2   0x00080000
86
87 static __u8 sc520cdp_read8(struct map_info *map, unsigned long ofs)
88 {
89         return readb(map->map_priv_1 + ofs);
90 }
91
92 static __u16 sc520cdp_read16(struct map_info *map, unsigned long ofs)
93 {
94         return readw(map->map_priv_1 + ofs);
95 }
96
97 static __u32 sc520cdp_read32(struct map_info *map, unsigned long ofs)
98 {
99         return readl(map->map_priv_1 + ofs);
100 }
101
102 static void sc520cdp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
103 {
104         memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
105 }
106
107 static void sc520cdp_write8(struct map_info *map, __u8 d, unsigned long adr)
108 {
109         writeb(d, map->map_priv_1 + adr);
110 }
111
112 static void sc520cdp_write16(struct map_info *map, __u16 d, unsigned long adr)
113 {
114         writew(d, map->map_priv_1 + adr);
115 }
116
117 static void sc520cdp_write32(struct map_info *map, __u32 d, unsigned long adr)
118 {
119         writel(d, map->map_priv_1 + adr);
120 }
121
122 static void sc520cdp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
123 {
124         memcpy_toio((void *)(map->map_priv_1 + to), from, len);
125 }
126
127 static struct map_info sc520cdp_map[] = {
128         {
129                 name: "SC520CDP Flash Bank #0",
130                 size: WINDOW_SIZE_0,
131                 buswidth: 4,
132                 read8: sc520cdp_read8,
133                 read16: sc520cdp_read16,
134                 read32: sc520cdp_read32,
135                 copy_from: sc520cdp_copy_from,
136                 write8: sc520cdp_write8,
137                 write16: sc520cdp_write16,
138                 write32: sc520cdp_write32,
139                 copy_to: sc520cdp_copy_to,
140                 map_priv_2: WINDOW_ADDR_0
141         },
142         {
143                 name: "SC520CDP Flash Bank #1",
144                 size: WINDOW_SIZE_1,
145                 buswidth: 4,
146                 read8: sc520cdp_read8,
147                 read16: sc520cdp_read16,
148                 read32: sc520cdp_read32,
149                 copy_from: sc520cdp_copy_from,
150                 write8: sc520cdp_write8,
151                 write16: sc520cdp_write16,
152                 write32: sc520cdp_write32,
153                 copy_to: sc520cdp_copy_to,
154                 map_priv_2: WINDOW_ADDR_1
155         },
156         {
157                 name: "SC520CDP DIL Flash",
158                 size: WINDOW_SIZE_2,
159                 buswidth: 1,
160                 read8: sc520cdp_read8,
161                 read16: sc520cdp_read16,
162                 read32: sc520cdp_read32,
163                 copy_from: sc520cdp_copy_from,
164                 write8: sc520cdp_write8,
165                 write16: sc520cdp_write16,
166                 write32: sc520cdp_write32,
167                 copy_to: sc520cdp_copy_to,
168                 map_priv_2: WINDOW_ADDR_2
169         },
170 };
171
172 #define NUM_FLASH_BANKS (sizeof(sc520cdp_map)/sizeof(struct map_info))
173
174 static struct mtd_info *mymtd[NUM_FLASH_BANKS];
175 static struct mtd_info *merged_mtd;
176
177 #ifdef REPROGRAM_PAR
178
179 /*
180 ** The SC520 MMCR (memory mapped control register) region resides
181 ** at 0xFFFEF000. The 16 Programmable Address Region (PAR) registers
182 ** are at offset 0x88 in the MMCR:
183 */
184 #define SC520_MMCR_BASE         0xFFFEF000
185 #define SC520_MMCR_EXTENT       0x1000
186 #define SC520_PAR(x)            ((0x88/sizeof(unsigned long)) + (x))
187 #define NUM_SC520_PAR           16      /* total number of PAR registers */
188
189 /*
190 ** The highest three bits in a PAR register determine what target
191 ** device is controlled by this PAR. Here, only ROMCS? and BOOTCS
192 ** devices are of interest.
193 */
194 #define SC520_PAR_BOOTCS        (0x4<<29)
195 #define SC520_PAR_ROMCS0        (0x5<<29)
196 #define SC520_PAR_ROMCS1        (0x6<<29)
197 #define SC520_PAR_TRGDEV        (0x7<<29)
198
199 /*
200 ** Bits 28 thru 26 determine some attributes for the
201 ** region controlled by the PAR. (We only use non-cacheable)
202 */
203 #define SC520_PAR_WRPROT        (1<<26) /* write protected       */
204 #define SC520_PAR_NOCACHE       (1<<27) /* non-cacheable         */
205 #define SC520_PAR_NOEXEC        (1<<28) /* code execution denied */
206
207
208 /*
209 ** Bit 25 determines the granularity: 4K or 64K
210 */
211 #define SC520_PAR_PG_SIZ4       (0<<25)
212 #define SC520_PAR_PG_SIZ64      (1<<25)
213
214 /*
215 ** Build a value to be written into a PAR register.
216 ** We only need ROM entries, 64K page size:
217 */
218 #define SC520_PAR_ENTRY(trgdev, address, size) \
219         ((trgdev) | SC520_PAR_NOCACHE | SC520_PAR_PG_SIZ64 | \
220         (address) >> 16 | (((size) >> 16) - 1) << 14)
221
222 struct sc520_par_table
223 {
224         unsigned long trgdev;
225         unsigned long new_par;
226         unsigned long default_address;
227 };
228
229 static struct sc520_par_table par_table[NUM_FLASH_BANKS] =
230 {
231         {       /* Flash Bank #0: selected by ROMCS0 */
232                 SC520_PAR_ROMCS0,
233                 SC520_PAR_ENTRY(SC520_PAR_ROMCS0, WINDOW_ADDR_0, WINDOW_SIZE_0),
234                 WINDOW_ADDR_0_BIOS
235         },
236         {       /* Flash Bank #1: selected by ROMCS1 */
237                 SC520_PAR_ROMCS1,
238                 SC520_PAR_ENTRY(SC520_PAR_ROMCS1, WINDOW_ADDR_1, WINDOW_SIZE_1),
239                 WINDOW_ADDR_1_BIOS
240         },
241         {       /* DIL (BIOS) Flash: selected by BOOTCS */
242                 SC520_PAR_BOOTCS,
243                 SC520_PAR_ENTRY(SC520_PAR_BOOTCS, WINDOW_ADDR_2, WINDOW_SIZE_2),
244                 WINDOW_ADDR_2_BIOS
245         }
246 };
247
248
249 static void sc520cdp_setup_par(void)
250 {
251         volatile unsigned long *mmcr;
252         unsigned long mmcr_val;
253         int i, j;
254
255         /* map in SC520's MMCR area */
256         mmcr = (unsigned long *)ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT);
257         if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */
258                 /* force map_priv_2 fields to BIOS defaults: */
259                 for(i = 0; i < NUM_FLASH_BANKS; i++)
260                         sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
261                 return;
262         }
263
264         /*
265         ** Find the PARxx registers that are reponsible for activating
266         ** ROMCS0, ROMCS1 and BOOTCS. Reprogram each of these with a
267         ** new value from the table.
268         */
269         for(i = 0; i < NUM_FLASH_BANKS; i++) {          /* for each par_table entry  */
270                 for(j = 0; j < NUM_SC520_PAR; j++) {    /* for each PAR register     */
271                         mmcr_val = mmcr[SC520_PAR(j)];
272                         /* if target device field matches, reprogram the PAR */
273                         if((mmcr_val & SC520_PAR_TRGDEV) == par_table[i].trgdev)
274                         {
275                                 mmcr[SC520_PAR(j)] = par_table[i].new_par;
276                                 break;
277                         }
278                 }
279                 if(j == NUM_SC520_PAR)
280                 {       /* no matching PAR found: try default BIOS address */
281                         printk(KERN_NOTICE "Could not find PAR responsible for %s\n",
282                                 sc520cdp_map[i].name);
283                         printk(KERN_NOTICE "Trying default address 0x%lx\n",
284                                 par_table[i].default_address);
285                         sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
286                 }
287         }
288         iounmap((void *)mmcr);
289 }
290 #endif
291
292
293 static int __init init_sc520cdp(void)
294 {
295         int i, devices_found = 0;
296         
297 #ifdef REPROGRAM_PAR
298         /* reprogram PAR registers so flash appears at the desired addresses */
299         sc520cdp_setup_par();
300 #endif
301
302         for (i = 0; i < NUM_FLASH_BANKS; i++) {
303                 printk(KERN_NOTICE "SC520 CDP flash device: %lx at %lx\n", sc520cdp_map[i].size, sc520cdp_map[i].map_priv_2);
304                 sc520cdp_map[i].map_priv_1 = (unsigned long)ioremap_nocache(sc520cdp_map[i].map_priv_2, sc520cdp_map[i].size);
305
306                 if (!sc520cdp_map[i].map_priv_1) {
307                         printk("Failed to ioremap_nocache\n");
308                         return -EIO;
309                 }
310                 mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]);
311                 if(!mymtd[i])
312                         mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]);
313                 if(!mymtd[i])
314                         mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]);
315
316                 if (mymtd[i]) {
317                         mymtd[i]->module = THIS_MODULE;
318                         ++devices_found;
319                 }
320                 else {
321                         iounmap((void *)sc520cdp_map[i].map_priv_1);
322                 }
323         }
324         if(devices_found >= 2) {
325                 /* Combine the two flash banks into a single MTD device & register it: */
326                 merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1");
327                 if(merged_mtd)
328                         add_mtd_device(merged_mtd);
329         }
330         if(devices_found == 3) /* register the third (DIL-Flash) device */
331                 add_mtd_device(mymtd[2]);
332         return(devices_found ? 0 : -ENXIO);
333 }
334
335 static void __exit cleanup_sc520cdp(void)
336 {
337         int i;
338         
339         if (merged_mtd) {
340                 del_mtd_device(merged_mtd);
341                 mtd_concat_destroy(merged_mtd);
342         }
343         if (mymtd[2])
344                 del_mtd_device(mymtd[2]);
345
346         for (i = 0; i < NUM_FLASH_BANKS; i++) {
347                 if (mymtd[i])
348                         map_destroy(mymtd[i]);
349                 if (sc520cdp_map[i].map_priv_1) {
350                         iounmap((void *)sc520cdp_map[i].map_priv_1);
351                         sc520cdp_map[i].map_priv_1 = 0;
352                 }
353         }
354 }
355
356 module_init(init_sc520cdp);
357 module_exit(cleanup_sc520cdp);
358
359 MODULE_LICENSE("GPL");
360 MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH");
361 MODULE_DESCRIPTION("MTD map driver for AMD SC520 Customer Development Platform");