diff options
-rw-r--r-- | drivers/mtd/chips/cfi_probe.c | 52 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_util.c | 62 | ||||
-rw-r--r-- | include/linux/mtd/cfi.h | 9 |
3 files changed, 73 insertions, 50 deletions
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index c418e92e1d92..e706be2ad0cb 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
@@ -44,17 +44,14 @@ do { \ | |||
44 | 44 | ||
45 | #define xip_enable(base, map, cfi) \ | 45 | #define xip_enable(base, map, cfi) \ |
46 | do { \ | 46 | do { \ |
47 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \ | 47 | qry_mode_off(base, map, cfi); \ |
48 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \ | ||
49 | xip_allowed(base, map); \ | 48 | xip_allowed(base, map); \ |
50 | } while (0) | 49 | } while (0) |
51 | 50 | ||
52 | #define xip_disable_qry(base, map, cfi) \ | 51 | #define xip_disable_qry(base, map, cfi) \ |
53 | do { \ | 52 | do { \ |
54 | xip_disable(); \ | 53 | xip_disable(); \ |
55 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \ | 54 | qry_mode_on(base, map, cfi); \ |
56 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \ | ||
57 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \ | ||
58 | } while (0) | 55 | } while (0) |
59 | 56 | ||
60 | #else | 57 | #else |
@@ -70,32 +67,6 @@ do { \ | |||
70 | in: interleave,type,mode | 67 | in: interleave,type,mode |
71 | ret: table index, <0 for error | 68 | ret: table index, <0 for error |
72 | */ | 69 | */ |
73 | static int __xipram qry_present(struct map_info *map, __u32 base, | ||
74 | struct cfi_private *cfi) | ||
75 | { | ||
76 | int osf = cfi->interleave * cfi->device_type; // scale factor | ||
77 | map_word val[3]; | ||
78 | map_word qry[3]; | ||
79 | |||
80 | qry[0] = cfi_build_cmd('Q', map, cfi); | ||
81 | qry[1] = cfi_build_cmd('R', map, cfi); | ||
82 | qry[2] = cfi_build_cmd('Y', map, cfi); | ||
83 | |||
84 | val[0] = map_read(map, base + osf*0x10); | ||
85 | val[1] = map_read(map, base + osf*0x11); | ||
86 | val[2] = map_read(map, base + osf*0x12); | ||
87 | |||
88 | if (!map_word_equal(map, qry[0], val[0])) | ||
89 | return 0; | ||
90 | |||
91 | if (!map_word_equal(map, qry[1], val[1])) | ||
92 | return 0; | ||
93 | |||
94 | if (!map_word_equal(map, qry[2], val[2])) | ||
95 | return 0; | ||
96 | |||
97 | return 1; // "QRY" found | ||
98 | } | ||
99 | 70 | ||
100 | static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | 71 | static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, |
101 | unsigned long *chip_map, struct cfi_private *cfi) | 72 | unsigned long *chip_map, struct cfi_private *cfi) |
@@ -116,11 +87,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
116 | } | 87 | } |
117 | 88 | ||
118 | xip_disable(); | 89 | xip_disable(); |
119 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 90 | if (!qry_mode_on(base, map, cfi)) { |
120 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
121 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | ||
122 | |||
123 | if (!qry_present(map,base,cfi)) { | ||
124 | xip_enable(base, map, cfi); | 91 | xip_enable(base, map, cfi); |
125 | return 0; | 92 | return 0; |
126 | } | 93 | } |
@@ -144,8 +111,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
144 | if (qry_present(map, start, cfi)) { | 111 | if (qry_present(map, start, cfi)) { |
145 | /* Eep. This chip also had the QRY marker. | 112 | /* Eep. This chip also had the QRY marker. |
146 | * Is it an alias for the new one? */ | 113 | * Is it an alias for the new one? */ |
147 | cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); | 114 | qry_mode_off(start, map, cfi); |
148 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | ||
149 | 115 | ||
150 | /* If the QRY marker goes away, it's an alias */ | 116 | /* If the QRY marker goes away, it's an alias */ |
151 | if (!qry_present(map, start, cfi)) { | 117 | if (!qry_present(map, start, cfi)) { |
@@ -158,8 +124,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
158 | * unfortunate. Stick the new chip in read mode | 124 | * unfortunate. Stick the new chip in read mode |
159 | * too and if it's the same, assume it's an alias. */ | 125 | * too and if it's the same, assume it's an alias. */ |
160 | /* FIXME: Use other modes to do a proper check */ | 126 | /* FIXME: Use other modes to do a proper check */ |
161 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 127 | qry_mode_off(base, map, cfi); |
162 | cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL); | ||
163 | 128 | ||
164 | if (qry_present(map, base, cfi)) { | 129 | if (qry_present(map, base, cfi)) { |
165 | xip_allowed(base, map); | 130 | xip_allowed(base, map); |
@@ -176,8 +141,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, | |||
176 | cfi->numchips++; | 141 | cfi->numchips++; |
177 | 142 | ||
178 | /* Put it back into Read Mode */ | 143 | /* Put it back into Read Mode */ |
179 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 144 | qry_mode_off(base, map, cfi); |
180 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
181 | xip_allowed(base, map); | 145 | xip_allowed(base, map); |
182 | 146 | ||
183 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", | 147 | printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n", |
@@ -237,9 +201,7 @@ static int __xipram cfi_chip_setup(struct map_info *map, | |||
237 | cfi_read_query(map, base + 0xf * ofs_factor); | 201 | cfi_read_query(map, base + 0xf * ofs_factor); |
238 | 202 | ||
239 | /* Put it back into Read Mode */ | 203 | /* Put it back into Read Mode */ |
240 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | 204 | qry_mode_off(base, map, cfi); |
241 | /* ... even if it's an Intel chip */ | ||
242 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
243 | xip_allowed(base, map); | 205 | xip_allowed(base, map); |
244 | 206 | ||
245 | /* Do any necessary byteswapping */ | 207 | /* Do any necessary byteswapping */ |
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 0ee457018016..8d7553670526 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c | |||
@@ -24,6 +24,62 @@ | |||
24 | #include <linux/mtd/cfi.h> | 24 | #include <linux/mtd/cfi.h> |
25 | #include <linux/mtd/compatmac.h> | 25 | #include <linux/mtd/compatmac.h> |
26 | 26 | ||
27 | int __xipram qry_present(struct map_info *map, __u32 base, | ||
28 | struct cfi_private *cfi) | ||
29 | { | ||
30 | int osf = cfi->interleave * cfi->device_type; /* scale factor */ | ||
31 | map_word val[3]; | ||
32 | map_word qry[3]; | ||
33 | |||
34 | qry[0] = cfi_build_cmd('Q', map, cfi); | ||
35 | qry[1] = cfi_build_cmd('R', map, cfi); | ||
36 | qry[2] = cfi_build_cmd('Y', map, cfi); | ||
37 | |||
38 | val[0] = map_read(map, base + osf*0x10); | ||
39 | val[1] = map_read(map, base + osf*0x11); | ||
40 | val[2] = map_read(map, base + osf*0x12); | ||
41 | |||
42 | if (!map_word_equal(map, qry[0], val[0])) | ||
43 | return 0; | ||
44 | |||
45 | if (!map_word_equal(map, qry[1], val[1])) | ||
46 | return 0; | ||
47 | |||
48 | if (!map_word_equal(map, qry[2], val[2])) | ||
49 | return 0; | ||
50 | |||
51 | return 1; /* "QRY" found */ | ||
52 | } | ||
53 | |||
54 | int __xipram qry_mode_on(uint32_t base, struct map_info *map, | ||
55 | struct cfi_private *cfi) | ||
56 | { | ||
57 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
58 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | ||
59 | if (qry_present(map, base, cfi)) | ||
60 | return 1; | ||
61 | /* QRY not found probably we deal with some odd CFI chips */ | ||
62 | /* Some revisions of some old Intel chips? */ | ||
63 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
64 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
65 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | ||
66 | if (qry_present(map, base, cfi)) | ||
67 | return 1; | ||
68 | /* ST M29DW chips */ | ||
69 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
70 | cfi_send_gen_cmd(0x98, 0x555, base, map, cfi, cfi->device_type, NULL); | ||
71 | if (qry_present(map, base, cfi)) | ||
72 | return 1; | ||
73 | /* QRY not found */ | ||
74 | return 0; | ||
75 | } | ||
76 | void __xipram qry_mode_off(uint32_t base, struct map_info *map, | ||
77 | struct cfi_private *cfi) | ||
78 | { | ||
79 | cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); | ||
80 | cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); | ||
81 | } | ||
82 | |||
27 | struct cfi_extquery * | 83 | struct cfi_extquery * |
28 | __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) | 84 | __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) |
29 | { | 85 | { |
@@ -48,8 +104,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
48 | #endif | 104 | #endif |
49 | 105 | ||
50 | /* Switch it into Query Mode */ | 106 | /* Switch it into Query Mode */ |
51 | cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); | 107 | qry_mode_on(base, map, cfi); |
52 | |||
53 | /* Read in the Extended Query Table */ | 108 | /* Read in the Extended Query Table */ |
54 | for (i=0; i<size; i++) { | 109 | for (i=0; i<size; i++) { |
55 | ((unsigned char *)extp)[i] = | 110 | ((unsigned char *)extp)[i] = |
@@ -57,8 +112,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n | |||
57 | } | 112 | } |
58 | 113 | ||
59 | /* Make sure it returns to read mode */ | 114 | /* Make sure it returns to read mode */ |
60 | cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL); | 115 | qry_mode_off(base, map, cfi); |
61 | cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL); | ||
62 | 116 | ||
63 | #ifdef CONFIG_MTD_XIP | 117 | #ifdef CONFIG_MTD_XIP |
64 | (void) map_read(map, base); | 118 | (void) map_read(map, base); |
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index d6fb115f5a07..3058917d7b92 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/mtd/flashchip.h> | 12 | #include <linux/mtd/flashchip.h> |
13 | #include <linux/mtd/map.h> | 13 | #include <linux/mtd/map.h> |
14 | #include <linux/mtd/cfi_endian.h> | 14 | #include <linux/mtd/cfi_endian.h> |
15 | #include <linux/mtd/xip.h> | ||
15 | 16 | ||
16 | #ifdef CONFIG_MTD_CFI_I1 | 17 | #ifdef CONFIG_MTD_CFI_I1 |
17 | #define cfi_interleave(cfi) 1 | 18 | #define cfi_interleave(cfi) 1 |
@@ -430,7 +431,6 @@ static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t | |||
430 | { | 431 | { |
431 | map_word val; | 432 | map_word val; |
432 | uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); | 433 | uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type); |
433 | |||
434 | val = cfi_build_cmd(cmd, map, cfi); | 434 | val = cfi_build_cmd(cmd, map, cfi); |
435 | 435 | ||
436 | if (prev_val) | 436 | if (prev_val) |
@@ -483,6 +483,13 @@ static inline void cfi_udelay(int us) | |||
483 | } | 483 | } |
484 | } | 484 | } |
485 | 485 | ||
486 | int __xipram qry_present(struct map_info *map, __u32 base, | ||
487 | struct cfi_private *cfi); | ||
488 | int __xipram qry_mode_on(uint32_t base, struct map_info *map, | ||
489 | struct cfi_private *cfi); | ||
490 | void __xipram qry_mode_off(uint32_t base, struct map_info *map, | ||
491 | struct cfi_private *cfi); | ||
492 | |||
486 | struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, | 493 | struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, |
487 | const char* name); | 494 | const char* name); |
488 | struct cfi_fixup { | 495 | struct cfi_fixup { |