fdt: Fix alignment issue when reading 64-bits properties from fdt
[oweals/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 <malloc.h>
14 #include <spi.h>
15 #include <spi_flash.h>
16
17 #include "sf_internal.h"
18
19 /**
20  * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
21  *
22  * @flashp: Pointer to place to put flash info, which may be NULL if the
23  * space should be allocated
24  */
25 static int spi_flash_probe_slave(struct spi_flash *flash)
26 {
27         struct spi_slave *spi = flash->spi;
28         int ret;
29
30         /* Setup spi_slave */
31         if (!spi) {
32                 printf("SF: Failed to set up slave\n");
33                 return -ENODEV;
34         }
35
36         /* Claim spi bus */
37         ret = spi_claim_bus(spi);
38         if (ret) {
39                 debug("SF: Failed to claim SPI bus: %d\n", ret);
40                 return ret;
41         }
42
43         ret = spi_nor_scan(flash);
44         if (ret)
45                 goto err_read_id;
46
47 #ifdef CONFIG_SPI_FLASH_MTD
48         ret = spi_flash_mtd_register(flash);
49 #endif
50
51 err_read_id:
52         spi_release_bus(spi);
53         return ret;
54 }
55
56 #ifndef CONFIG_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 #ifdef CONFIG_SPI_FLASH_MTD
87         spi_flash_mtd_unregister();
88 #endif
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                 printf("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 static int spi_flash_std_probe(struct udevice *dev)
141 {
142         struct spi_slave *slave = dev_get_parent_priv(dev);
143         struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
144         struct spi_flash *flash;
145
146         flash = dev_get_uclass_priv(dev);
147         flash->dev = dev;
148         flash->spi = slave;
149         debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs);
150         return spi_flash_probe_slave(flash);
151 }
152
153 static int spi_flash_std_remove(struct udevice *dev)
154 {
155 #ifdef CONFIG_SPI_FLASH_MTD
156         spi_flash_mtd_unregister();
157 #endif
158         return 0;
159 }
160
161 static const struct dm_spi_flash_ops spi_flash_std_ops = {
162         .read = spi_flash_std_read,
163         .write = spi_flash_std_write,
164         .erase = spi_flash_std_erase,
165         .get_sw_write_prot = spi_flash_std_get_sw_write_prot,
166 };
167
168 static const struct udevice_id spi_flash_std_ids[] = {
169         { .compatible = "jedec,spi-nor" },
170         { }
171 };
172
173 U_BOOT_DRIVER(spi_flash_std) = {
174         .name           = "spi_flash_std",
175         .id             = UCLASS_SPI_FLASH,
176         .of_match       = spi_flash_std_ids,
177         .probe          = spi_flash_std_probe,
178         .remove         = spi_flash_std_remove,
179         .priv_auto_alloc_size = sizeof(struct spi_flash),
180         .ops            = &spi_flash_std_ops,
181 };
182
183 #endif /* CONFIG_DM_SPI_FLASH */