blob: e192f97efdc4f76ef5bca8d9b941ea31fdee57ab [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +05302/*
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.
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +05308 */
9
10#include <common.h>
Simon Glass6f7d2592014-10-13 23:42:07 -060011#include <dm.h>
Simon Glassc10c3d42014-10-13 23:42:05 -060012#include <errno.h>
Chin-Ting Kuo77636df2022-08-19 17:01:09 +080013#include <linux/mtd/spi-nor.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053015#include <malloc.h>
16#include <spi.h>
17#include <spi_flash.h>
Chin-Ting Kuo77636df2022-08-19 17:01:09 +080018#include <spi-mem.h>
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053019
Jagannadha Sutradharudu Tekiac8242d2013-09-26 16:00:15 +053020#include "sf_internal.h"
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053021
Chin-Ting Kuo77636df2022-08-19 17:01:09 +080022static 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
50static 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
Simon Glassc10c3d42014-10-13 23:42:05 -060076/**
77 * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
78 *
Simon Glassc10c3d42014-10-13 23:42:05 -060079 * @flashp: Pointer to place to put flash info, which may be NULL if the
80 * space should be allocated
81 */
Jagan Tekic772eaa2015-12-06 21:44:12 +053082static int spi_flash_probe_slave(struct spi_flash *flash)
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053083{
Jagan Teki4abfb982015-12-06 21:33:32 +053084 struct spi_slave *spi = flash->spi;
Jagannadha Sutradharudu Tekibb302202013-09-24 16:01:23 +053085 int ret;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053086
Jagannadha Sutradharudu Tekibb302202013-09-24 16:01:23 +053087 /* Setup spi_slave */
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053088 if (!spi) {
89 printf("SF: Failed to set up slave\n");
Simon Glassc10c3d42014-10-13 23:42:05 -060090 return -ENODEV;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053091 }
92
Jagannadha Sutradharudu Tekibb302202013-09-24 16:01:23 +053093 /* Claim spi bus */
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053094 ret = spi_claim_bus(spi);
95 if (ret) {
96 debug("SF: Failed to claim SPI bus: %d\n", ret);
Simon Glassc10c3d42014-10-13 23:42:05 -060097 return ret;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +053098 }
99
Vignesh R14510412019-02-05 11:29:23 +0530100 ret = spi_nor_scan(flash);
Simon Glass07f66712016-02-24 09:14:56 -0700101 if (ret)
Jagannadha Sutradharudu Tekibb302202013-09-24 16:01:23 +0530102 goto err_read_id;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530103
Chin-Ting Kuo77636df2022-08-19 17:01:09 +0800104 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
Jagan Teki380cdbe2020-05-13 00:11:27 +0530114 if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
115 ret = spi_flash_mtd_register(flash);
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530116
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530117err_read_id:
118 spi_release_bus(spi);
Simon Glassc10c3d42014-10-13 23:42:05 -0600119 return ret;
120}
121
Lukasz Majewski76f442982020-06-04 23:11:53 +0800122#if !CONFIG_IS_ENABLED(DM_SPI_FLASH)
Mario Six5f4c1342018-01-15 11:08:42 +0100123struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
124 unsigned int max_hz, unsigned int spi_mode)
Simon Glassc10c3d42014-10-13 23:42:05 -0600125{
Mario Six5f4c1342018-01-15 11:08:42 +0100126 struct spi_slave *bus;
Simon Glassc10c3d42014-10-13 23:42:05 -0600127 struct spi_flash *flash;
128
Mario Six5f4c1342018-01-15 11:08:42 +0100129 bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
130 if (!bus)
131 return NULL;
132
Simon Glassc10c3d42014-10-13 23:42:05 -0600133 /* 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
Jagan Teki4abfb982015-12-06 21:33:32 +0530140 flash->spi = bus;
141 if (spi_flash_probe_slave(flash)) {
Simon Glassc10c3d42014-10-13 23:42:05 -0600142 spi_free_slave(bus);
143 free(flash);
144 return NULL;
145 }
146
147 return flash;
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530148}
149
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530150void spi_flash_free(struct spi_flash *flash)
151{
Chin-Ting Kuo77636df2022-08-19 17:01:09 +0800152 if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
153 spi_mem_dirmap_destroy(flash->dirmap.wdesc);
154 spi_mem_dirmap_destroy(flash->dirmap.rdesc);
155 }
156
Jagan Teki380cdbe2020-05-13 00:11:27 +0530157 if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
Marek Behúnc1fcc142021-05-26 14:08:20 +0200158 spi_flash_mtd_unregister(flash);
Jagan Teki380cdbe2020-05-13 00:11:27 +0530159
Jagannadha Sutradharudu Tekie9a8b822013-08-29 19:01:56 +0530160 spi_free_slave(flash->spi);
161 free(flash);
162}
Simon Glass6f7d2592014-10-13 23:42:07 -0600163
164#else /* defined CONFIG_DM_SPI_FLASH */
165
166static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
167 void *buf)
168{
Simon Glassde0977b2015-03-05 12:25:20 -0700169 struct spi_flash *flash = dev_get_uclass_priv(dev);
Vignesh R14510412019-02-05 11:29:23 +0530170 struct mtd_info *mtd = &flash->mtd;
171 size_t retlen;
Simon Glass6f7d2592014-10-13 23:42:07 -0600172
Vignesh R14510412019-02-05 11:29:23 +0530173 return log_ret(mtd->_read(mtd, offset, len, &retlen, buf));
Simon Glass6f7d2592014-10-13 23:42:07 -0600174}
175
Jagan Tekic772eaa2015-12-06 21:44:12 +0530176static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
Mario Sixc9214d82018-01-15 11:08:40 +0100177 const void *buf)
Simon Glass6f7d2592014-10-13 23:42:07 -0600178{
Simon Glassde0977b2015-03-05 12:25:20 -0700179 struct spi_flash *flash = dev_get_uclass_priv(dev);
Vignesh R14510412019-02-05 11:29:23 +0530180 struct mtd_info *mtd = &flash->mtd;
181 size_t retlen;
Simon Glass6f7d2592014-10-13 23:42:07 -0600182
Vignesh R14510412019-02-05 11:29:23 +0530183 return mtd->_write(mtd, offset, len, &retlen, buf);
Simon Glass6f7d2592014-10-13 23:42:07 -0600184}
185
Jagan Tekic772eaa2015-12-06 21:44:12 +0530186static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
Simon Glass6f7d2592014-10-13 23:42:07 -0600187{
Simon Glassde0977b2015-03-05 12:25:20 -0700188 struct spi_flash *flash = dev_get_uclass_priv(dev);
Vignesh R14510412019-02-05 11:29:23 +0530189 struct mtd_info *mtd = &flash->mtd;
190 struct erase_info instr;
191
192 if (offset % mtd->erasesize || len % mtd->erasesize) {
Simon Glass03f31012020-07-19 10:15:32 -0600193 debug("SF: Erase offset/length not multiple of erase size\n");
Vignesh R14510412019-02-05 11:29:23 +0530194 return -EINVAL;
195 }
196
197 memset(&instr, 0, sizeof(instr));
198 instr.addr = offset;
199 instr.len = len;
Simon Glass6f7d2592014-10-13 23:42:07 -0600200
Vignesh R14510412019-02-05 11:29:23 +0530201 return mtd->_erase(mtd, &instr);
Simon Glass6f7d2592014-10-13 23:42:07 -0600202}
203
Simon Glass61d04642021-03-15 18:11:17 +1300204static 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
Simon Glassa104b642019-12-06 21:42:50 -0700211int spi_flash_std_probe(struct udevice *dev)
Simon Glass6f7d2592014-10-13 23:42:07 -0600212{
Simon Glassde44acf2015-09-28 23:32:01 -0600213 struct spi_slave *slave = dev_get_parent_priv(dev);
Simon Glass6f7d2592014-10-13 23:42:07 -0600214 struct spi_flash *flash;
215
Simon Glassde0977b2015-03-05 12:25:20 -0700216 flash = dev_get_uclass_priv(dev);
Simon Glass6f7d2592014-10-13 23:42:07 -0600217 flash->dev = dev;
Jagan Teki4abfb982015-12-06 21:33:32 +0530218 flash->spi = slave;
Jagan Teki4abfb982015-12-06 21:33:32 +0530219 return spi_flash_probe_slave(flash);
Simon Glass6f7d2592014-10-13 23:42:07 -0600220}
221
Boris Brezillon4be0c812018-12-02 10:54:31 +0100222static int spi_flash_std_remove(struct udevice *dev)
223{
Marek Behúnc1fcc142021-05-26 14:08:20 +0200224 struct spi_flash *flash = dev_get_uclass_priv(dev);
Pratyush Yadav46103502021-06-26 00:47:24 +0530225 int ret;
226
Chin-Ting Kuo77636df2022-08-19 17:01:09 +0800227 if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
228 spi_mem_dirmap_destroy(flash->dirmap.wdesc);
229 spi_mem_dirmap_destroy(flash->dirmap.rdesc);
230 }
231
Pratyush Yadav46103502021-06-26 00:47:24 +0530232 ret = spi_nor_remove(flash);
233 if (ret)
234 return ret;
Marek Behúnc1fcc142021-05-26 14:08:20 +0200235
Jagan Teki380cdbe2020-05-13 00:11:27 +0530236 if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
Marek Behúnc1fcc142021-05-26 14:08:20 +0200237 spi_flash_mtd_unregister(flash);
Jagan Teki380cdbe2020-05-13 00:11:27 +0530238
Boris Brezillon4be0c812018-12-02 10:54:31 +0100239 return 0;
240}
241
Simon Glass6f7d2592014-10-13 23:42:07 -0600242static 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,
Simon Glass61d04642021-03-15 18:11:17 +1300246 .get_sw_write_prot = spi_flash_std_get_sw_write_prot,
Simon Glass6f7d2592014-10-13 23:42:07 -0600247};
248
249static const struct udevice_id spi_flash_std_ids[] = {
Vignesh R54c8a672019-02-05 11:29:22 +0530250 { .compatible = "jedec,spi-nor" },
Simon Glass6f7d2592014-10-13 23:42:07 -0600251 { }
252};
253
Walter Lozano2901ac62020-06-25 01:10:04 -0300254U_BOOT_DRIVER(jedec_spi_nor) = {
255 .name = "jedec_spi_nor",
Simon Glass6f7d2592014-10-13 23:42:07 -0600256 .id = UCLASS_SPI_FLASH,
257 .of_match = spi_flash_std_ids,
258 .probe = spi_flash_std_probe,
Boris Brezillon4be0c812018-12-02 10:54:31 +0100259 .remove = spi_flash_std_remove,
Simon Glassb33cd252020-12-19 10:40:01 -0700260 .priv_auto = sizeof(struct spi_nor),
Simon Glass6f7d2592014-10-13 23:42:07 -0600261 .ops = &spi_flash_std_ops,
Pratyush Yadav46103502021-06-26 00:47:24 +0530262 .flags = DM_FLAG_OS_PREPARE,
Simon Glass6f7d2592014-10-13 23:42:07 -0600263};
264
Simon Glassdf65db82020-12-28 20:34:57 -0700265DM_DRIVER_ALIAS(jedec_spi_nor, spansion_m25p16)
Walter Lozano48e5b042020-06-25 01:10:06 -0300266
Simon Glass6f7d2592014-10-13 23:42:07 -0600267#endif /* CONFIG_DM_SPI_FLASH */