aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.4/1110-mtd-spi-nor-fsl-quad-add-flash-S25FS-extra-support.patch
blob: 20149b137ac55cb920e386aa7e43bb570cd489ad (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
From 034dd6241b55ab2256eecb845e941fa9b45da38e Mon Sep 17 00:00:00 2001
From: Yunhui Cui <yunhui.cui@nxp.com>
Date: Thu, 28 Apr 2016 17:03:57 +0800
Subject: [PATCH 110/113] mtd: spi-nor: fsl-quad: add flash S25FS extra
 support

[context adjustment]
not apply changes of arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts

There are some boards have the same QSPI controller but have
different vendor flash, So, the controller can use the same
compatible and share the driver, just for a different flash to do
the appropriate adaptation. Based on this, we need add the vendor
field in spi-nor, Because we will use the field to distribute
corresponding LUT for different flash operations.

Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
Signed-off-by: Pratiyush Mohan Srivastava <pratiyush.srivastava@nxp.com>
Signed-off-by: Prabhakar Kushwaha <prabhakar.kushwaha@nxp.com>
Integrated-by: Jiang Yutang <yutang.jiang@nxp.com>
---
 drivers/mtd/spi-nor/fsl-quadspi.c |   47 ++++++++++++++++++++++++++++++-------
 drivers/mtd/spi-nor/spi-nor.c     |    5 ++--
 include/linux/mtd/spi-nor.h       |    1 +
 3 files changed, 42 insertions(+), 11 deletions(-)

--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -213,6 +213,9 @@
 
 #define QUADSPI_MIN_IOMAP SZ_4M
 
+#define FLASH_VENDOR_SPANSION_FS	"s25fs"
+#define SPANSION_S25FS_FAMILY	(1 << 1)
+
 enum fsl_qspi_devtype {
 	FSL_QUADSPI_VYBRID,
 	FSL_QUADSPI_IMX6SX,
@@ -329,6 +332,18 @@ static inline int has_added_amba_base_in
 	return q->devtype_data->driver_data & QUADSPI_AMBA_BASE_INTERNAL;
 }
 
+static u32 fsl_get_nor_vendor(struct spi_nor *nor)
+{
+	u32 vendor_id;
+
+	if (nor->vendor) {
+		if (memcmp(nor->vendor, FLASH_VENDOR_SPANSION_FS,
+					sizeof(FLASH_VENDOR_SPANSION_FS) - 1))
+			vendor_id = SPANSION_S25FS_FAMILY;
+	}
+	return vendor_id;
+}
+
 /*
  * R/W functions for big- or little-endian registers:
  * The qSPI controller's endian is independent of the CPU core's endian.
@@ -394,13 +409,15 @@ static void fsl_qspi_init_lut(struct fsl
 	int rxfifo = q->devtype_data->rxfifo;
 	u32 lut_base;
 	int i;
-	const struct fsl_qspi_devtype_data *devtype_data = q->devtype_data;
+	u32 vendor;
 
 	struct spi_nor *nor = &q->nor[0];
 	u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
 	u8 read_op = nor->read_opcode;
 	u8 read_dm = nor->read_dummy;
 
+	vendor = fsl_get_nor_vendor(nor);
+
 	fsl_qspi_unlock_lut(q);
 
 	/* Clear all the LUT table */
@@ -418,12 +435,25 @@ static void fsl_qspi_init_lut(struct fsl
 			    LUT1(FSL_READ, PAD1, rxfifo),
 				base + QUADSPI_LUT(lut_base + 1));
 	} else if (nor->flash_read == SPI_NOR_QUAD) {
-		qspi_writel(q, LUT0(CMD, PAD1, read_op) |
-			    LUT1(ADDR, PAD1, addrlen),
-				base + QUADSPI_LUT(lut_base));
-		qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) |
-			    LUT1(FSL_READ, PAD4, rxfifo),
-				base + QUADSPI_LUT(lut_base + 1));
+		if (q->nor_size == 0x4000000) {
+			read_op = 0xEC;
+		qspi_writel(q,
+			LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD4, addrlen),
+			base + QUADSPI_LUT(lut_base));
+		qspi_writel(q,
+			LUT0(MODE, PAD4, 0xff) | LUT1(DUMMY, PAD4, read_dm),
+			base + QUADSPI_LUT(lut_base + 1));
+		qspi_writel(q,
+			LUT0(FSL_READ, PAD4, rxfifo),
+			base + QUADSPI_LUT(lut_base + 2));
+		} else {
+			qspi_writel(q, LUT0(CMD, PAD1, read_op) |
+				    LUT1(ADDR, PAD1, addrlen),
+					base + QUADSPI_LUT(lut_base));
+			qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) |
+				    LUT1(FSL_READ, PAD4, rxfifo),
+					base + QUADSPI_LUT(lut_base + 1));
+		}
 	} else if (nor->flash_read == SPI_NOR_DDR_QUAD) {
 		/* read mode : 1-4-4, such as Spansion s25fl128s. */
 		qspi_writel(q, LUT0(CMD, PAD1, read_op)
@@ -510,7 +540,8 @@ static void fsl_qspi_init_lut(struct fsl
 	 * use the same value 0x65. But it indicates different meaning.
 	 */
 	lut_base = SEQID_RDAR_OR_RD_EVCR * 4;
-	if (devtype_data->devtype == FSL_QUADSPI_LS2080A) {
+
+	if (vendor == SPANSION_S25FS_FAMILY) {
 		/*
 		* Read any device register.
 		* Used for Spansion S25FS-S family flash only.
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -804,7 +804,6 @@ static const struct flash_info spi_nor_i
 	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, 0)},
-	{ "s25fs512s",  INFO6(0x010220, 0x4d0081, 128 * 1024, 512, 0)},
 	{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
 	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
 	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
@@ -971,11 +970,9 @@ static int spansion_s25fs_disable_4kb_er
 	ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1);
 	if (ret)
 		return ret;
-/*
 	if (!(cr3v & CR3V_4KB_ERASE_UNABLE))
 		return -EPERM;
 
-*/
 	return 0;
 }
 
@@ -1349,6 +1346,8 @@ int spi_nor_scan(struct spi_nor *nor, co
 
 	if (!mtd->name)
 		mtd->name = dev_name(dev);
+	if (info->name)
+		nor->vendor = info->name;
 	mtd->priv = nor;
 	mtd->type = MTD_NORFLASH;
 	mtd->writesize = 1;
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -172,6 +172,7 @@ struct spi_nor {
 	bool			sst_write_second;
 	u32			flags;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+	char			*vendor;
 
 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);