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