]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
4d5e29a6 JT |
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. | |
4d5e29a6 JT |
8 | */ |
9 | ||
10 | #include <common.h> | |
fbb09918 | 11 | #include <dm.h> |
ae242cbf | 12 | #include <errno.h> |
f7ae49fc | 13 | #include <log.h> |
4d5e29a6 JT |
14 | #include <malloc.h> |
15 | #include <spi.h> | |
16 | #include <spi_flash.h> | |
17 | ||
898e76c9 | 18 | #include "sf_internal.h" |
4d5e29a6 | 19 | |
ae242cbf SG |
20 | /** |
21 | * spi_flash_probe_slave() - Probe for a SPI flash device on a bus | |
22 | * | |
ae242cbf SG |
23 | * @flashp: Pointer to place to put flash info, which may be NULL if the |
24 | * space should be allocated | |
25 | */ | |
339fd6dc | 26 | static int spi_flash_probe_slave(struct spi_flash *flash) |
4d5e29a6 | 27 | { |
bfdb07eb | 28 | struct spi_slave *spi = flash->spi; |
4d4ec992 | 29 | int ret; |
4d5e29a6 | 30 | |
4d4ec992 | 31 | /* Setup spi_slave */ |
4d5e29a6 JT |
32 | if (!spi) { |
33 | printf("SF: Failed to set up slave\n"); | |
ae242cbf | 34 | return -ENODEV; |
4d5e29a6 JT |
35 | } |
36 | ||
4d4ec992 | 37 | /* Claim spi bus */ |
4d5e29a6 JT |
38 | ret = spi_claim_bus(spi); |
39 | if (ret) { | |
40 | debug("SF: Failed to claim SPI bus: %d\n", ret); | |
ae242cbf | 41 | return ret; |
4d5e29a6 JT |
42 | } |
43 | ||
c4e88623 | 44 | ret = spi_nor_scan(flash); |
0badb23d | 45 | if (ret) |
4d4ec992 | 46 | goto err_read_id; |
4d5e29a6 | 47 | |
3ee152b9 JT |
48 | if (CONFIG_IS_ENABLED(SPI_FLASH_MTD)) |
49 | ret = spi_flash_mtd_register(flash); | |
4d5e29a6 | 50 | |
4d5e29a6 JT |
51 | err_read_id: |
52 | spi_release_bus(spi); | |
ae242cbf SG |
53 | return ret; |
54 | } | |
55 | ||
56c40460 | 56 | #if !CONFIG_IS_ENABLED(DM_SPI_FLASH) |
36890ff0 MS |
57 | struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, |
58 | unsigned int max_hz, unsigned int spi_mode) | |
ae242cbf | 59 | { |
36890ff0 | 60 | struct spi_slave *bus; |
ae242cbf SG |
61 | struct spi_flash *flash; |
62 | ||
36890ff0 MS |
63 | bus = spi_setup_slave(busnum, cs, max_hz, spi_mode); |
64 | if (!bus) | |
65 | return NULL; | |
66 | ||
ae242cbf SG |
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 | ||
bfdb07eb JT |
74 | flash->spi = bus; |
75 | if (spi_flash_probe_slave(flash)) { | |
ae242cbf SG |
76 | spi_free_slave(bus); |
77 | free(flash); | |
78 | return NULL; | |
79 | } | |
80 | ||
81 | return flash; | |
4d5e29a6 JT |
82 | } |
83 | ||
4d5e29a6 JT |
84 | void spi_flash_free(struct spi_flash *flash) |
85 | { | |
3ee152b9 | 86 | if (CONFIG_IS_ENABLED(SPI_FLASH_MTD)) |
b7f06056 | 87 | spi_flash_mtd_unregister(flash); |
3ee152b9 | 88 | |
4d5e29a6 JT |
89 | spi_free_slave(flash->spi); |
90 | free(flash); | |
91 | } | |
fbb09918 SG |
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 | { | |
e564f054 | 98 | struct spi_flash *flash = dev_get_uclass_priv(dev); |
c4e88623 V |
99 | struct mtd_info *mtd = &flash->mtd; |
100 | size_t retlen; | |
fbb09918 | 101 | |
c4e88623 | 102 | return log_ret(mtd->_read(mtd, offset, len, &retlen, buf)); |
fbb09918 SG |
103 | } |
104 | ||
339fd6dc | 105 | static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len, |
a3e32c50 | 106 | const void *buf) |
fbb09918 | 107 | { |
e564f054 | 108 | struct spi_flash *flash = dev_get_uclass_priv(dev); |
c4e88623 V |
109 | struct mtd_info *mtd = &flash->mtd; |
110 | size_t retlen; | |
fbb09918 | 111 | |
c4e88623 | 112 | return mtd->_write(mtd, offset, len, &retlen, buf); |
fbb09918 SG |
113 | } |
114 | ||
339fd6dc | 115 | static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) |
fbb09918 | 116 | { |
e564f054 | 117 | struct spi_flash *flash = dev_get_uclass_priv(dev); |
c4e88623 V |
118 | struct mtd_info *mtd = &flash->mtd; |
119 | struct erase_info instr; | |
120 | ||
121 | if (offset % mtd->erasesize || len % mtd->erasesize) { | |
e567ec84 | 122 | debug("SF: Erase offset/length not multiple of erase size\n"); |
c4e88623 V |
123 | return -EINVAL; |
124 | } | |
125 | ||
126 | memset(&instr, 0, sizeof(instr)); | |
127 | instr.addr = offset; | |
128 | instr.len = len; | |
fbb09918 | 129 | |
c4e88623 | 130 | return mtd->_erase(mtd, &instr); |
fbb09918 SG |
131 | } |
132 | ||
b3b60f59 SG |
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 | ||
4806fcea | 140 | int spi_flash_std_probe(struct udevice *dev) |
fbb09918 | 141 | { |
bcbe3d15 | 142 | struct spi_slave *slave = dev_get_parent_priv(dev); |
fbb09918 SG |
143 | struct spi_flash *flash; |
144 | ||
e564f054 | 145 | flash = dev_get_uclass_priv(dev); |
fbb09918 | 146 | flash->dev = dev; |
bfdb07eb | 147 | flash->spi = slave; |
bfdb07eb | 148 | return spi_flash_probe_slave(flash); |
fbb09918 SG |
149 | } |
150 | ||
7371944a BB |
151 | static int spi_flash_std_remove(struct udevice *dev) |
152 | { | |
b7f06056 MB |
153 | struct spi_flash *flash = dev_get_uclass_priv(dev); |
154 | ||
3ee152b9 | 155 | if (CONFIG_IS_ENABLED(SPI_FLASH_MTD)) |
b7f06056 | 156 | spi_flash_mtd_unregister(flash); |
3ee152b9 | 157 | |
7371944a BB |
158 | return 0; |
159 | } | |
160 | ||
fbb09918 SG |
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, | |
b3b60f59 | 165 | .get_sw_write_prot = spi_flash_std_get_sw_write_prot, |
fbb09918 SG |
166 | }; |
167 | ||
168 | static const struct udevice_id spi_flash_std_ids[] = { | |
2ee6705b | 169 | { .compatible = "jedec,spi-nor" }, |
fbb09918 SG |
170 | { } |
171 | }; | |
172 | ||
e3e2470f WL |
173 | U_BOOT_DRIVER(jedec_spi_nor) = { |
174 | .name = "jedec_spi_nor", | |
fbb09918 SG |
175 | .id = UCLASS_SPI_FLASH, |
176 | .of_match = spi_flash_std_ids, | |
177 | .probe = spi_flash_std_probe, | |
7371944a | 178 | .remove = spi_flash_std_remove, |
a1a8a633 | 179 | .priv_auto = sizeof(struct spi_nor), |
fbb09918 SG |
180 | .ops = &spi_flash_std_ops, |
181 | }; | |
182 | ||
bdf8fd76 | 183 | DM_DRIVER_ALIAS(jedec_spi_nor, spansion_m25p16) |
addf358b | 184 | |
fbb09918 | 185 | #endif /* CONFIG_DM_SPI_FLASH */ |