2 * Common Flash Interface support:
3 * Generic utility functions not dependant on command set
5 * Copyright (C) 2002 Red Hat
6 * Copyright (C) 2003 STMicroelectronics Limited
8 * This code is covered by the GPL.
10 * $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $
14 #include <linux/module.h>
15 #include <linux/types.h>
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
19 #include <asm/byteorder.h>
21 #include <linux/errno.h>
22 #include <linux/slab.h>
23 #include <linux/delay.h>
24 #include <linux/interrupt.h>
25 #include <linux/mtd/xip.h>
26 #include <linux/mtd/mtd.h>
27 #include <linux/mtd/map.h>
28 #include <linux/mtd/cfi.h>
29 #include <linux/mtd/compatmac.h>
32 __xipram
cfi_read_pri(struct map_info
*map
, __u16 adr
, __u16 size
, const char* name
)
34 struct cfi_private
*cfi
= map
->fldrv_priv
;
35 __u32 base
= 0; // cfi->chips[0].start;
36 int ofs_factor
= cfi
->interleave
* cfi
->device_type
;
38 struct cfi_extquery
*extp
= NULL
;
40 printk(" %s Extended Query Table at 0x%4.4X\n", name
, adr
);
44 extp
= kmalloc(size
, GFP_KERNEL
);
46 printk(KERN_ERR
"Failed to allocate memory\n");
54 /* Switch it into Query Mode */
55 cfi_send_gen_cmd(0x98, 0x55, base
, map
, cfi
, cfi
->device_type
, NULL
);
57 /* Read in the Extended Query Table */
58 for (i
=0; i
<size
; i
++) {
59 ((unsigned char *)extp
)[i
] =
60 cfi_read_query(map
, base
+((adr
+i
)*ofs_factor
));
63 /* Make sure it returns to read mode */
64 cfi_send_gen_cmd(0xf0, 0, base
, map
, cfi
, cfi
->device_type
, NULL
);
65 cfi_send_gen_cmd(0xff, 0, base
, map
, cfi
, cfi
->device_type
, NULL
);
68 (void) map_read(map
, base
);
69 asm volatile (".rep 8; nop; .endr");
73 if (extp
->MajorVersion
!= '1' ||
74 (extp
->MinorVersion
< '0' || extp
->MinorVersion
> '3')) {
75 printk(KERN_WARNING
" Unknown %s Extended Query "
76 "version %c.%c.\n", name
, extp
->MajorVersion
,
85 EXPORT_SYMBOL(cfi_read_pri
);
87 void cfi_fixup(struct mtd_info
*mtd
, struct cfi_fixup
*fixups
)
89 struct map_info
*map
= mtd
->priv
;
90 struct cfi_private
*cfi
= map
->fldrv_priv
;
93 for (f
=fixups
; f
->fixup
; f
++) {
94 if (((f
->mfr
== CFI_MFR_ANY
) || (f
->mfr
== cfi
->mfr
)) &&
95 ((f
->id
== CFI_ID_ANY
) || (f
->id
== cfi
->id
))) {
96 f
->fixup(mtd
, f
->param
);
101 EXPORT_SYMBOL(cfi_fixup
);
103 int cfi_varsize_frob(struct mtd_info
*mtd
, varsize_frob_t frob
,
104 loff_t ofs
, size_t len
, void *thunk
)
106 struct map_info
*map
= mtd
->priv
;
107 struct cfi_private
*cfi
= map
->fldrv_priv
;
109 int chipnum
, ret
= 0;
111 struct mtd_erase_region_info
*regions
= mtd
->eraseregions
;
116 if ((len
+ ofs
) > mtd
->size
)
119 /* Check that both start and end of the requested erase are
120 * aligned with the erasesize at the appropriate addresses.
125 /* Skip all erase regions which are ended before the start of
126 the requested erase. Actually, to save on the calculations,
127 we skip to the first erase region which starts after the
128 start of the requested erase, and then go back one.
131 while (i
< mtd
->numeraseregions
&& ofs
>= regions
[i
].offset
)
135 /* OK, now i is pointing at the erase region in which this
136 erase request starts. Check the start of the requested
137 erase range is aligned with the erase size which is in
141 if (ofs
& (regions
[i
].erasesize
-1))
144 /* Remember the erase region we start on */
147 /* Next, check that the end of the requested erase is aligned
148 * with the erase region at that address.
151 while (i
<mtd
->numeraseregions
&& (ofs
+ len
) >= regions
[i
].offset
)
154 /* As before, drop back one to point at the region in which
155 the address actually falls
159 if ((ofs
+ len
) & (regions
[i
].erasesize
-1))
162 chipnum
= ofs
>> cfi
->chipshift
;
163 adr
= ofs
- (chipnum
<< cfi
->chipshift
);
168 int size
= regions
[i
].erasesize
;
170 ret
= (*frob
)(map
, &cfi
->chips
[chipnum
], adr
, size
, thunk
);
179 if (ofs
== regions
[i
].offset
+ size
* regions
[i
].numblocks
)
182 if (adr
>> cfi
->chipshift
) {
186 if (chipnum
>= cfi
->numchips
)
194 EXPORT_SYMBOL(cfi_varsize_frob
);
196 MODULE_LICENSE("GPL");