aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Korolev <akorolev@infradead.org>2008-08-05 11:39:42 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2008-08-06 04:43:58 -0400
commit2e489e077a6ad118c4f247faedf330117b107cce (patch)
treeb40cbd8863ce2faf98d7c2717891d0a2b11b6557
parenta0e7229edbfef9495e73bc8baea2131a7e69e365 (diff)
[MTD] [NOR] Add qry_mode_on()/qry_omde_off() to deal with odd chips
There are some CFI chips which require non standard procedures to get into QRY mode. The possible way to support them would be trying different modes till QRY will be read. This patch introduce two new functions qry_mode_on qry_mode_off. qry_mode_on tries different commands in order switch chip into QRY mode. So if we have one more "odd" chip - we just could add several lines to qry_mode_on. Also using these functions remove unnecessary code duplicaton in porbe procedure. Currently there are two "odd" cases 1. Some old intel chips which require 0xFF before 0x98 2. ST M29DW chip which requires 0x98 to be sent at 0x555 (according to CFI should be 0x55) This patch is partialy based on the patch from Uwe (see "[PATCH 2/4] [RFC][MTD] cfi_probe: remove Intel chip workaround" thread ) Signed-off-by: Alexey Korolev <akorolev@infradead.org> Signed-off-by: Alexander Belyakov <abelyako@gmail.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--drivers/mtd/chips/cfi_probe.c52
-rw-r--r--drivers/mtd/chips/cfi_util.c62
-rw-r--r--include/linux/mtd/cfi.h9
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) \
46do { \ 46do { \
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) \
53do { \ 52do { \
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 */
73static 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
100static int __xipram cfi_probe_chip(struct map_info *map, __u32 base, 71static 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
27int __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
54int __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}
76void __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
27struct cfi_extquery * 83struct 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
486int __xipram qry_present(struct map_info *map, __u32 base,
487 struct cfi_private *cfi);
488int __xipram qry_mode_on(uint32_t base, struct map_info *map,
489 struct cfi_private *cfi);
490void __xipram qry_mode_off(uint32_t base, struct map_info *map,
491 struct cfi_private *cfi);
492
486struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, 493struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size,
487 const char* name); 494 const char* name);
488struct cfi_fixup { 495struct cfi_fixup {