Skip to content

Commit 2e489e0

Browse files
Alexey KorolevDavid Woodhouse
authored andcommitted
[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>
1 parent a0e7229 commit 2e489e0

File tree

3 files changed

+73
-50
lines changed

3 files changed

+73
-50
lines changed

drivers/mtd/chips/cfi_probe.c

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,14 @@ do { \
4444

4545
#define xip_enable(base, map, cfi) \
4646
do { \
47-
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
48-
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
47+
qry_mode_off(base, map, cfi); \
4948
xip_allowed(base, map); \
5049
} while (0)
5150

5251
#define xip_disable_qry(base, map, cfi) \
5352
do { \
5453
xip_disable(); \
55-
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
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); \
54+
qry_mode_on(base, map, cfi); \
5855
} while (0)
5956

6057
#else
@@ -70,32 +67,6 @@ do { \
7067
in: interleave,type,mode
7168
ret: table index, <0 for error
7269
*/
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-
}
9970

10071
static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
10172
unsigned long *chip_map, struct cfi_private *cfi)
@@ -116,11 +87,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
11687
}
11788

11889
xip_disable();
119-
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
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)) {
90+
if (!qry_mode_on(base, map, cfi)) {
12491
xip_enable(base, map, cfi);
12592
return 0;
12693
}
@@ -144,8 +111,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
144111
if (qry_present(map, start, cfi)) {
145112
/* Eep. This chip also had the QRY marker.
146113
* Is it an alias for the new one? */
147-
cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
148-
cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
114+
qry_mode_off(start, map, cfi);
149115

150116
/* If the QRY marker goes away, it's an alias */
151117
if (!qry_present(map, start, cfi)) {
@@ -158,8 +124,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
158124
* unfortunate. Stick the new chip in read mode
159125
* too and if it's the same, assume it's an alias. */
160126
/* FIXME: Use other modes to do a proper check */
161-
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
162-
cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
127+
qry_mode_off(base, map, cfi);
163128

164129
if (qry_present(map, base, cfi)) {
165130
xip_allowed(base, map);
@@ -176,8 +141,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
176141
cfi->numchips++;
177142

178143
/* Put it back into Read Mode */
179-
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
180-
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
144+
qry_mode_off(base, map, cfi);
181145
xip_allowed(base, map);
182146

183147
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,
237201
cfi_read_query(map, base + 0xf * ofs_factor);
238202

239203
/* Put it back into Read Mode */
240-
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
241-
/* ... even if it's an Intel chip */
242-
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
204+
qry_mode_off(base, map, cfi);
243205
xip_allowed(base, map);
244206

245207
/* Do any necessary byteswapping */

drivers/mtd/chips/cfi_util.c

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,62 @@
2424
#include <linux/mtd/cfi.h>
2525
#include <linux/mtd/compatmac.h>
2626

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+
2783
struct cfi_extquery *
2884
__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
2985
{
@@ -48,17 +104,15 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
48104
#endif
49105

50106
/* Switch it into Query Mode */
51-
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
52-
107+
qry_mode_on(base, map, cfi);
53108
/* Read in the Extended Query Table */
54109
for (i=0; i<size; i++) {
55110
((unsigned char *)extp)[i] =
56111
cfi_read_query(map, base+((adr+i)*ofs_factor));
57112
}
58113

59114
/* Make sure it returns to read mode */
60-
cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
61-
cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
115+
qry_mode_off(base, map, cfi);
62116

63117
#ifdef CONFIG_MTD_XIP
64118
(void) map_read(map, base);

include/linux/mtd/cfi.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/mtd/flashchip.h>
1313
#include <linux/mtd/map.h>
1414
#include <linux/mtd/cfi_endian.h>
15+
#include <linux/mtd/xip.h>
1516

1617
#ifdef CONFIG_MTD_CFI_I1
1718
#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
430431
{
431432
map_word val;
432433
uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type);
433-
434434
val = cfi_build_cmd(cmd, map, cfi);
435435

436436
if (prev_val)
@@ -483,6 +483,13 @@ static inline void cfi_udelay(int us)
483483
}
484484
}
485485

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+
486493
struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size,
487494
const char* name);
488495
struct cfi_fixup {

0 commit comments

Comments
 (0)