aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
blob: e41fd3fff74d284682630ff4c417fef726bde002 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
From 96b232d03a0c4462eacf879ed80b0cfd235e65c4 Mon Sep 17 00:00:00 2001
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Date: Fri, 8 Jan 2016 17:02:17 +0100
Subject: [PATCH 20/33] mtd: spi-nor: fix support of Winbond memories

This patch fixes the support of Winbond memories. Indeed, before
performing any Quad SPI command, the Quad Enable (QE) non-volatile bit
MUST be set in the Status Register 2.

According to the w25q16fw datasheet from Winbond:
"When QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3."

Quad SPI instructions requires the bidirectional IO2 and IO3 pins.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 100 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h   |   6 +++
 2 files changed, 106 insertions(+)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 1b1f5a6..aa7d26d 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1166,6 +1166,40 @@ static int spansion_quad_enable(struct spi_nor *nor)
 	return 0;
 }
 
+static int winbond_quad_enable(struct spi_nor *nor)
+{
+	int ret;
+	u8 sr2;
+
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
+	if (ret < 0)
+		return ret;
+
+	if (likely(sr2 & SR2_QUAD_EN_WINB))
+		return 0;
+	dev_warn(nor->dev, "Winbond Quad mode disabled, enable it\n");
+
+	write_enable(nor);
+
+	sr2 |= SR2_QUAD_EN_WINB;
+	ret = nor->write_reg(nor, SPINOR_OP_WRSR2_WINB, &sr2, 1);
+	if (ret < 0)
+		return ret;
+
+	if (spi_nor_wait_till_ready(nor))
+		return -EIO;
+
+	ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
+	if (ret < 0)
+		return ret;
+	if (!(sr2 & SR2_QUAD_EN_WINB)) {
+		dev_err(nor->dev, "Winbond Quad bit not set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int macronix_set_quad_mode(struct spi_nor *nor)
 {
 	int status;
@@ -1226,6 +1260,63 @@ static int macronix_set_single_mode(struct spi_nor *nor)
 	return 0;
 }
 
+static int winbond_set_quad_mode(struct spi_nor *nor)
+{
+	int status;
+
+	/* Check whether the QPI mode is enabled. */
+	if (nor->read_proto == SNOR_PROTO_4_4_4) {
+		/* Since the QPI mode is enabled, the Quad Enabled (QE)
+		 * non-volatile bit is already set.
+		 * If the Fast Read 1-4-4 (0xeb) were used, we should
+		 * take care about the value M7-M0 written during
+		 * dummy/mode cycles to avoid entering the continuous
+		 * read mode by  mistake.
+		 * Also the Fast Read 1-1-4 (0x6b) op code is not
+		 * supported in QPI mode.
+		 * Hence the Fast Read 1-1-1 (0x0b) op code is chosen.
+		 */
+		nor->read_opcode = SPINOR_OP_READ_FAST;
+		return 0;
+	}
+
+	/*
+	 * The QPI mode is disabled but we still need to set the QE bit:
+	 * when QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3.
+	 * If the Fast Read 1-4-4 (0xeb) were used, we should take care
+	 * about the value M7-M0 written during dummy/mode cycles to
+	 * avoid entering the continuous read mode by mistake.
+	 * Hence the Fast Read 1-1-4 (0x6b) op code is preferred.
+	 */
+	status = winbond_quad_enable(nor);
+	if (status) {
+		dev_err(nor->dev, "Winbond quad-read nor enabled\n");
+		return status;
+	}
+	nor->read_proto = SNOR_PROTO_1_1_4;
+	nor->read_opcode = SPINOR_OP_READ_1_1_4;
+	return 0;
+}
+
+/*
+ * For both Winbond Dual and Single modes, we don't care about the value of
+ * the Quad Enabled (QE) bit since the memory still replies to Dual or Single
+ * SPI commands.
+ */
+
+static int winbond_set_dual_mode(struct spi_nor *nor)
+{
+	nor->read_proto = SNOR_PROTO_1_1_2;
+	nor->read_opcode = SPINOR_OP_READ_1_1_2;
+	return 0;
+}
+
+static int winbond_set_single_mode(struct spi_nor *nor)
+{
+	nor->read_proto = SNOR_PROTO_1_1_1;
+	return 0;
+}
+
 static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 {
 	int status;
@@ -1234,6 +1325,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
 	case SNOR_MFR_MACRONIX:
 		return macronix_set_quad_mode(nor);
 
+	case SNOR_MFR_WINBOND:
+		return winbond_set_quad_mode(nor);
+
 	case SNOR_MFR_MICRON:
 		/* Check whether Micron Quad mode is enabled. */
 		if (nor->read_proto != SNOR_PROTO_4_4_4)
@@ -1263,6 +1357,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
 	case SNOR_MFR_MACRONIX:
 		return macronix_set_dual_mode(nor);
 
+	case SNOR_MFR_WINBOND:
+		return winbond_set_dual_mode(nor);
+
 	case SNOR_MFR_MICRON:
 		/* Check whether Micron Dual mode is enabled. */
 		if (nor->read_proto != SNOR_PROTO_2_2_2)
@@ -1284,6 +1381,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
 	case SNOR_MFR_MACRONIX:
 		return macronix_set_single_mode(nor);
 
+	case SNOR_MFR_WINBOND:
+		return winbond_set_single_mode(nor);
+
 	default:
 		nor->read_proto = SNOR_PROTO_1_1_1;
 		break;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 89e3228..46343f5 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -75,6 +75,12 @@
 #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
 #define SPINOR_OP_EX4B		0xe9	/* Exit 4-byte mode */
 
+/* Used for Winbond flashes only. */
+#define SPINOR_OP_RDSR2_WINB	0x35	/* Read status register 2 */
+#define SPINOR_OP_WRSR2_WINB	0x31	/* Write status register 2 */
+
+#define SR2_QUAD_EN_WINB	BIT(1)	/* Quad Enable bit */
+
 /* Used for Spansion flashes only. */
 #define SPINOR_OP_BRWR		0x17	/* Bank register write */
 
-- 
2.8.1