1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * SPI flash probing
4 *
5 * Copyright (C) 2008 Atmel Corporation
6 * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
7 * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
8 */
9
10 #include <dm.h>
11 #include <errno.h>
12 #include <linux/mtd/spi-nor.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <spi.h>
16 #include <spi_flash.h>
17 #include <spi-mem.h>
18
19 #include "sf_internal.h"
20
spi_nor_create_read_dirmap(struct spi_nor * nor)21 static int spi_nor_create_read_dirmap(struct spi_nor *nor)
22 {
23 struct spi_mem_dirmap_info info = {
24 .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
25 SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
26 SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
27 SPI_MEM_OP_DATA_IN(0, NULL, 0)),
28 .offset = 0,
29 .length = nor->mtd.size,
30 };
31 struct spi_mem_op *op = &info.op_tmpl;
32
33 /* get transfer protocols. */
34 spi_nor_setup_op(nor, op, nor->read_proto);
35 op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
36
37 /* convert the dummy cycles to the number of bytes */
38 op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8;
39 if (spi_nor_protocol_is_dtr(nor->read_proto))
40 op->dummy.nbytes *= 2;
41
42 nor->dirmap.rdesc = spi_mem_dirmap_create(nor->spi, &info);
43 if (IS_ERR(nor->dirmap.rdesc))
44 return PTR_ERR(nor->dirmap.rdesc);
45
46 return 0;
47 }
48
spi_nor_create_write_dirmap(struct spi_nor * nor)49 static int spi_nor_create_write_dirmap(struct spi_nor *nor)
50 {
51 struct spi_mem_dirmap_info info = {
52 .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0),
53 SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
54 SPI_MEM_OP_NO_DUMMY,
55 SPI_MEM_OP_DATA_OUT(0, NULL, 0)),
56 .offset = 0,
57 .length = nor->mtd.size,
58 };
59 struct spi_mem_op *op = &info.op_tmpl;
60
61 /* get transfer protocols. */
62 spi_nor_setup_op(nor, op, nor->write_proto);
63 op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
64
65 if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
66 op->addr.nbytes = 0;
67
68 nor->dirmap.wdesc = spi_mem_dirmap_create(nor->spi, &info);
69 if (IS_ERR(nor->dirmap.wdesc))
70 return PTR_ERR(nor->dirmap.wdesc);
71
72 return 0;
73 }
74
75 /**
76 * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
77 *
78 * @flashp: Pointer to place to put flash info, which may be NULL if the
79 * space should be allocated
80 */
spi_flash_probe_slave(struct spi_flash * flash)81 static int spi_flash_probe_slave(struct spi_flash *flash)
82 {
83 struct spi_slave *spi = flash->spi;
84 int ret;
85
86 /* Setup spi_slave */
87 if (!spi) {
88 printf("SF: Failed to set up slave\n");
89 return -ENODEV;
90 }
91
92 /* Claim spi bus */
93 ret = spi_claim_bus(spi);
94 if (ret) {
95 debug("SF: Failed to claim SPI bus: %d\n", ret);
96 return ret;
97 }
98
99 ret = spi_nor_scan(flash);
100 if (ret)
101 goto err_read_id;
102
103 if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
104 ret = spi_nor_create_read_dirmap(flash);
105 if (ret)
106 return ret;
107
108 ret = spi_nor_create_write_dirmap(flash);
109 if (ret)
110 return ret;
111 }
112
113 if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
114 ret = spi_flash_mtd_register(flash);
115
116 err_read_id:
117 spi_release_bus(spi);
118 return ret;
119 }
120
121 #if !CONFIG_IS_ENABLED(DM_SPI_FLASH)
spi_flash_probe(unsigned int busnum,unsigned int cs,unsigned int max_hz,unsigned int spi_mode)122 struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
123 unsigned int max_hz, unsigned int spi_mode)
124 {
125 struct spi_slave *bus;
126 struct spi_flash *flash;
127
128 bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
129 if (!bus)
130 return NULL;
131
132 /* Allocate space if needed (not used by sf-uclass */
133 flash = calloc(1, sizeof(*flash));
134 if (!flash) {
135 debug("SF: Failed to allocate spi_flash\n");
136 return NULL;
137 }
138
139 flash->spi = bus;
140 if (spi_flash_probe_slave(flash)) {
141 spi_free_slave(bus);
142 free(flash);
143 return NULL;
144 }
145
146 return flash;
147 }
148
spi_flash_free(struct spi_flash * flash)149 void spi_flash_free(struct spi_flash *flash)
150 {
151 if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
152 spi_mem_dirmap_destroy(flash->dirmap.wdesc);
153 spi_mem_dirmap_destroy(flash->dirmap.rdesc);
154 }
155
156 if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
157 spi_flash_mtd_unregister(flash);
158
159 spi_free_slave(flash->spi);
160 free(flash);
161 }
162
163 #else /* defined CONFIG_DM_SPI_FLASH */
164
spi_flash_std_read(struct udevice * dev,u32 offset,size_t len,void * buf)165 static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
166 void *buf)
167 {
168 struct spi_flash *flash = dev_get_uclass_priv(dev);
169 struct mtd_info *mtd = &flash->mtd;
170 size_t retlen;
171
172 return log_ret(mtd->_read(mtd, offset, len, &retlen, buf));
173 }
174
spi_flash_std_write(struct udevice * dev,u32 offset,size_t len,const void * buf)175 static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
176 const void *buf)
177 {
178 struct spi_flash *flash = dev_get_uclass_priv(dev);
179 struct mtd_info *mtd = &flash->mtd;
180 size_t retlen;
181
182 return mtd->_write(mtd, offset, len, &retlen, buf);
183 }
184
spi_flash_std_erase(struct udevice * dev,u32 offset,size_t len)185 static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
186 {
187 struct spi_flash *flash = dev_get_uclass_priv(dev);
188 struct mtd_info *mtd = &flash->mtd;
189 struct erase_info instr;
190
191 if (!mtd->erasesize ||
192 (offset % mtd->erasesize || len % mtd->erasesize)) {
193 debug("SF: Erase offset/length not multiple of erase size\n");
194 return -EINVAL;
195 }
196
197 memset(&instr, 0, sizeof(instr));
198 instr.addr = offset;
199 instr.len = len;
200
201 return mtd->_erase(mtd, &instr);
202 }
203
spi_flash_std_get_sw_write_prot(struct udevice * dev)204 static int spi_flash_std_get_sw_write_prot(struct udevice *dev)
205 {
206 struct spi_flash *flash = dev_get_uclass_priv(dev);
207
208 return spi_flash_cmd_get_sw_write_prot(flash);
209 }
210
spi_flash_std_probe(struct udevice * dev)211 int spi_flash_std_probe(struct udevice *dev)
212 {
213 struct spi_slave *slave = dev_get_parent_priv(dev);
214 struct spi_flash *flash;
215
216 flash = dev_get_uclass_priv(dev);
217 flash->dev = dev;
218 flash->spi = slave;
219 return spi_flash_probe_slave(flash);
220 }
221
spi_flash_std_remove(struct udevice * dev)222 static int spi_flash_std_remove(struct udevice *dev)
223 {
224 struct spi_flash *flash = dev_get_uclass_priv(dev);
225 int ret;
226
227 if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
228 spi_mem_dirmap_destroy(flash->dirmap.wdesc);
229 spi_mem_dirmap_destroy(flash->dirmap.rdesc);
230 }
231
232 ret = spi_nor_remove(flash);
233 if (ret)
234 return ret;
235
236 if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
237 spi_flash_mtd_unregister(flash);
238
239 return 0;
240 }
241
242 static const struct dm_spi_flash_ops spi_flash_std_ops = {
243 .read = spi_flash_std_read,
244 .write = spi_flash_std_write,
245 .erase = spi_flash_std_erase,
246 .get_sw_write_prot = spi_flash_std_get_sw_write_prot,
247 };
248
249 static const struct udevice_id spi_flash_std_ids[] = {
250 { .compatible = "jedec,spi-nor" },
251 { }
252 };
253
254 U_BOOT_DRIVER(jedec_spi_nor) = {
255 .name = "jedec_spi_nor",
256 .id = UCLASS_SPI_FLASH,
257 .of_match = spi_flash_std_ids,
258 .probe = spi_flash_std_probe,
259 .remove = spi_flash_std_remove,
260 .priv_auto = sizeof(struct spi_nor),
261 .ops = &spi_flash_std_ops,
262 .flags = DM_FLAG_OS_PREPARE,
263 };
264
265 DM_DRIVER_ALIAS(jedec_spi_nor, spansion_m25p16)
266
267 #endif /* CONFIG_DM_SPI_FLASH */
268