Merge tag 'tpm-030822' of https://source.denx.de/u-boot/custodians/u-boot-tpm
[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 <log.h>
14 #include <malloc.h>
15 #include <spi.h>
16 #include <spi_flash.h>
17
18 #include "sf_internal.h"
19
20 /**
21  * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
22  *
23  * @flashp: Pointer to place to put flash info, which may be NULL if the
24  * space should be allocated
25  */
26 static int spi_flash_probe_slave(struct spi_flash *flash)
27 {
28         struct spi_slave *spi = flash->spi;
29         int ret;
30
31         /* Setup spi_slave */
32         if (!spi) {
33                 printf("SF: Failed to set up slave\n");
34                 return -ENODEV;
35         }
36
37         /* Claim spi bus */
38         ret = spi_claim_bus(spi);
39         if (ret) {
40                 debug("SF: Failed to claim SPI bus: %d\n", ret);
41                 return ret;
42         }
43
44         ret = spi_nor_scan(flash);
45         if (ret)
46                 goto err_read_id;
47
48         if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
49                 ret = spi_flash_mtd_register(flash);
50
51 err_read_id:
52         spi_release_bus(spi);
53         return ret;
54 }
55
56 #if !CONFIG_IS_ENABLED(DM_SPI_FLASH)
57 struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
58                                   unsigned int max_hz, unsigned int spi_mode)
59 {
60         struct spi_slave *bus;
61         struct spi_flash *flash;
62
63         bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
64         if (!bus)
65                 return NULL;
66
67         /* Allocate space if needed (not used by sf-uclass */
68         flash = calloc(1, sizeof(*flash));
69         if (!flash) {
70                 debug("SF: Failed to allocate spi_flash\n");
71                 return NULL;
72         }
73
74         flash->spi = bus;
75         if (spi_flash_probe_slave(flash)) {
76                 spi_free_slave(bus);
77                 free(flash);
78                 return NULL;
79         }
80
81         return flash;
82 }
83
84 void spi_flash_free(struct spi_flash *flash)
85 {
86         if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
87                 spi_flash_mtd_unregister(flash);
88
89         spi_free_slave(flash->spi);
90         free(flash);
91 }
92
93 #else /* defined CONFIG_DM_SPI_FLASH */
94
95 static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
96                               void *buf)
97 {
98         struct spi_flash *flash = dev_get_uclass_priv(dev);
99         struct mtd_info *mtd = &flash->mtd;
100         size_t retlen;
101
102         return log_ret(mtd->_read(mtd, offset, len, &retlen, buf));
103 }
104
105 static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
106                                const void *buf)
107 {
108         struct spi_flash *flash = dev_get_uclass_priv(dev);
109         struct mtd_info *mtd = &flash->mtd;
110         size_t retlen;
111
112         return mtd->_write(mtd, offset, len, &retlen, buf);
113 }
114
115 static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
116 {
117         struct spi_flash *flash = dev_get_uclass_priv(dev);
118         struct mtd_info *mtd = &flash->mtd;
119         struct erase_info instr;
120
121         if (offset % mtd->erasesize || len % mtd->erasesize) {
122                 debug("SF: Erase offset/length not multiple of erase size\n");
123                 return -EINVAL;
124         }
125
126         memset(&instr, 0, sizeof(instr));
127         instr.addr = offset;
128         instr.len = len;
129
130         return mtd->_erase(mtd, &instr);
131 }
132
133 static int spi_flash_std_get_sw_write_prot(struct udevice *dev)
134 {
135         struct spi_flash *flash = dev_get_uclass_priv(dev);
136
137         return spi_flash_cmd_get_sw_write_prot(flash);
138 }
139
140 int spi_flash_std_probe(struct udevice *dev)
141 {
142         struct spi_slave *slave = dev_get_parent_priv(dev);
143         struct spi_flash *flash;
144
145         flash = dev_get_uclass_priv(dev);
146         flash->dev = dev;
147         flash->spi = slave;
148         return spi_flash_probe_slave(flash);
149 }
150
151 static int spi_flash_std_remove(struct udevice *dev)
152 {
153         struct spi_flash *flash = dev_get_uclass_priv(dev);
154         int ret;
155
156         ret = spi_nor_remove(flash);
157         if (ret)
158                 return ret;
159
160         if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
161                 spi_flash_mtd_unregister(flash);
162
163         return 0;
164 }
165
166 static const struct dm_spi_flash_ops spi_flash_std_ops = {
167         .read = spi_flash_std_read,
168         .write = spi_flash_std_write,
169         .erase = spi_flash_std_erase,
170         .get_sw_write_prot = spi_flash_std_get_sw_write_prot,
171 };
172
173 static const struct udevice_id spi_flash_std_ids[] = {
174         { .compatible = "jedec,spi-nor" },
175         { }
176 };
177
178 U_BOOT_DRIVER(jedec_spi_nor) = {
179         .name           = "jedec_spi_nor",
180         .id             = UCLASS_SPI_FLASH,
181         .of_match       = spi_flash_std_ids,
182         .probe          = spi_flash_std_probe,
183         .remove         = spi_flash_std_remove,
184         .priv_auto      = sizeof(struct spi_nor),
185         .ops            = &spi_flash_std_ops,
186         .flags          = DM_FLAG_OS_PREPARE,
187 };
188
189 DM_DRIVER_ALIAS(jedec_spi_nor, spansion_m25p16)
190
191 #endif /* CONFIG_DM_SPI_FLASH */