aboutsummaryrefslogtreecommitdiffstats
path: root/package/boot/uboot-mediatek/patches/100-14-mtd-spi-nor-add-support-to-read-flash-unique-ID.patch
blob: 6a61045955e8c1cf3d9d860a6512806d5e6e0b32 (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
From c4172a95df8a57a66c70a8b9948b9600a01c4cb7 Mon Sep 17 00:00:00 2001
From: Weijie Gao <weijie.gao@mediatek.com>
Date: Mon, 25 Jul 2022 11:32:08 +0800
Subject: [PATCH 49/71] mtd: spi-nor: add support to read flash unique ID

This patch adds support to read unique ID from spi-nor flashes.

Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
---
 drivers/mtd/spi/spi-nor-core.c | 95 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h    |  2 +
 2 files changed, 97 insertions(+)

--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2742,6 +2742,100 @@ static int spi_nor_init_params(struct sp
 	return 0;
 }
 
+static int spi_nor_read_uuid(struct spi_nor *nor)
+{
+	u8 read_opcode, addr_width, read_dummy;
+	loff_t addr;
+	u8 *uuid;
+	u8 uuid_len;
+	int shift = 0;
+	int ret;
+	int i;
+	struct spi_mem_op op;
+
+	read_opcode = nor->read_opcode;
+	addr_width = nor->addr_width;
+	read_dummy = nor->read_dummy;
+
+	switch (JEDEC_MFR(nor->info)) {
+	case SNOR_MFR_WINBOND:
+		uuid_len = 8;
+		nor->read_opcode = 0x4b;
+		nor->addr_width = 0;
+		addr = 0x0;
+		nor->read_dummy = 4;
+		break;
+	case SNOR_MFR_GIGADEVICE:
+		uuid_len = 16;
+		nor->read_opcode = 0x4b;
+		nor->addr_width = 3;
+		addr = 0x0;
+		nor->read_dummy = 1;
+		break;
+	case CFI_MFR_ST:
+	case SNOR_MFR_MICRON:
+		uuid_len = 17;
+		shift = 3;
+		nor->read_opcode = 0x9f;
+		nor->addr_width = 0;
+		addr = 0x0;
+		nor->read_dummy = 0;
+		break;
+	case SNOR_MFR_EON:
+		uuid_len = 12;
+		nor->read_opcode = 0x5a;
+		nor->addr_width = 3;
+		addr = 0x80;
+		nor->read_dummy = 1;
+		break;
+	/* Automotive only in SPANSION's NOR devices */
+	case SNOR_MFR_SPANSION:
+		uuid_len = 11;
+		shift = 386;
+		nor->read_opcode = 0x9f;
+		nor->addr_width = 0;
+		addr = 0x0;
+		nor->read_dummy = 0;
+		break;
+	default:
+		printf("UUID not supported on this device.\n");
+		return -ENOTSUPP;
+	}
+
+	uuid = kmalloc((uuid_len + shift) * sizeof(*uuid), GFP_KERNEL);
+	if (!uuid) {
+		ret = -ENOMEM;
+		goto read_err;
+	}
+	memset(uuid, 0x0, (uuid_len + shift) * sizeof(*uuid));
+
+	op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
+					   SPI_MEM_OP_ADDR(nor->addr_width, addr, 0),
+					   SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
+					   SPI_MEM_OP_DATA_IN(uuid_len+shift, NULL, 0));
+
+	spi_nor_setup_op(nor, &op, nor->reg_proto);
+
+	ret = spi_nor_read_write_reg(nor, &op, uuid);
+	if (ret < 0) {
+		dev_dbg(nor->dev, "error %d reading %x\n", ret, nor->read_opcode);
+		goto read_err;
+	}
+
+	printf("UUID: 0x");
+	for(i = 0; i<uuid_len; i++)
+		printf("%02x", uuid[i+shift]);
+	puts("\n");
+
+read_err:
+	nor->read_opcode = read_opcode;
+	nor->addr_width = addr_width;
+	nor->read_dummy = read_dummy;
+	kfree(uuid);
+
+	return ret;
+}
+
 static int spi_nor_hwcaps2cmd(u32 hwcaps, const int table[][2], size_t size)
 {
 	size_t i;
@@ -3719,6 +3813,7 @@ int spi_nor_scan(struct spi_nor *nor)
 	nor->write = spi_nor_write_data;
 	nor->read_reg = spi_nor_read_reg;
 	nor->write_reg = spi_nor_write_reg;
+	nor->read_uuid = spi_nor_read_uuid;
 
 	nor->setup = spi_nor_default_setup;
 
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -28,6 +28,7 @@
 #define SNOR_MFR_SPANSION	CFI_MFR_AMD
 #define SNOR_MFR_SST		CFI_MFR_SST
 #define SNOR_MFR_WINBOND	0xef /* Also used by some Spansion */
+#define SNOR_MFR_EON		CFI_MFR_EON
 #define SNOR_MFR_CYPRESS	0x34
 
 /*
@@ -547,6 +548,7 @@ struct spi_nor {
 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
 	int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
+	int (*read_uuid)(struct spi_nor *nor);
 
 	ssize_t (*read)(struct spi_nor *nor, loff_t from,
 			size_t len, u_char *read_buf);