1898e76c9SJagannadha Sutradharudu Teki /*
2898e76c9SJagannadha Sutradharudu Teki * SPI flash probing
3898e76c9SJagannadha Sutradharudu Teki *
4898e76c9SJagannadha Sutradharudu Teki * Copyright (C) 2008 Atmel Corporation
5898e76c9SJagannadha Sutradharudu Teki * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
6898e76c9SJagannadha Sutradharudu Teki * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc.
7898e76c9SJagannadha Sutradharudu Teki *
80c88a84aSJagannadha Sutradharudu Teki * SPDX-License-Identifier: GPL-2.0+
9898e76c9SJagannadha Sutradharudu Teki */
10898e76c9SJagannadha Sutradharudu Teki
11898e76c9SJagannadha Sutradharudu Teki #include <common.h>
12a5ce032fSJason Zhu #include <blk.h>
13fbb09918SSimon Glass #include <dm.h>
14ae242cbfSSimon Glass #include <errno.h>
15898e76c9SJagannadha Sutradharudu Teki #include <malloc.h>
16898e76c9SJagannadha Sutradharudu Teki #include <spi.h>
17898e76c9SJagannadha Sutradharudu Teki #include <spi_flash.h>
18898e76c9SJagannadha Sutradharudu Teki
19898e76c9SJagannadha Sutradharudu Teki #include "sf_internal.h"
20898e76c9SJagannadha Sutradharudu Teki
21ae242cbfSSimon Glass /**
22ae242cbfSSimon Glass * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
23ae242cbfSSimon Glass *
24ae242cbfSSimon Glass * @flashp: Pointer to place to put flash info, which may be NULL if the
25ae242cbfSSimon Glass * space should be allocated
26ae242cbfSSimon Glass */
spi_flash_probe_slave(struct spi_flash * flash)27339fd6dcSJagan Teki static int spi_flash_probe_slave(struct spi_flash *flash)
28898e76c9SJagannadha Sutradharudu Teki {
29bfdb07ebSJagan Teki struct spi_slave *spi = flash->spi;
30898e76c9SJagannadha Sutradharudu Teki int ret;
31898e76c9SJagannadha Sutradharudu Teki
32898e76c9SJagannadha Sutradharudu Teki /* Setup spi_slave */
33898e76c9SJagannadha Sutradharudu Teki if (!spi) {
34898e76c9SJagannadha Sutradharudu Teki printf("SF: Failed to set up slave\n");
35ae242cbfSSimon Glass return -ENODEV;
36898e76c9SJagannadha Sutradharudu Teki }
37898e76c9SJagannadha Sutradharudu Teki
38898e76c9SJagannadha Sutradharudu Teki /* Claim spi bus */
39898e76c9SJagannadha Sutradharudu Teki ret = spi_claim_bus(spi);
40898e76c9SJagannadha Sutradharudu Teki if (ret) {
41898e76c9SJagannadha Sutradharudu Teki debug("SF: Failed to claim SPI bus: %d\n", ret);
42ae242cbfSSimon Glass return ret;
43898e76c9SJagannadha Sutradharudu Teki }
44898e76c9SJagannadha Sutradharudu Teki
45*951aa503SJon Lin #if !CONFIG_IS_ENABLED(SPI_FLASH_TINY)
46*951aa503SJon Lin flash->mtd.name = (char *)ofnode_read_string(spi->dev->node, "label");
47*951aa503SJon Lin #endif
48*951aa503SJon Lin
49f2313133SVignesh R ret = spi_nor_scan(flash);
500badb23dSSimon Glass if (ret)
51898e76c9SJagannadha Sutradharudu Teki goto err_read_id;
52898e76c9SJagannadha Sutradharudu Teki
539fe6d871SDaniel Schwierzeck #ifdef CONFIG_SPI_FLASH_MTD
549fe6d871SDaniel Schwierzeck ret = spi_flash_mtd_register(flash);
559fe6d871SDaniel Schwierzeck #endif
56898e76c9SJagannadha Sutradharudu Teki
57898e76c9SJagannadha Sutradharudu Teki err_read_id:
58898e76c9SJagannadha Sutradharudu Teki spi_release_bus(spi);
59ae242cbfSSimon Glass return ret;
60ae242cbfSSimon Glass }
61ae242cbfSSimon Glass
62fbb09918SSimon Glass #ifndef CONFIG_DM_SPI_FLASH
spi_flash_probe(unsigned int busnum,unsigned int cs,unsigned int max_hz,unsigned int spi_mode)638a91194bSMario Six struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
648a91194bSMario Six unsigned int max_hz, unsigned int spi_mode)
65ae242cbfSSimon Glass {
668a91194bSMario Six struct spi_slave *bus;
67ae242cbfSSimon Glass struct spi_flash *flash;
68ae242cbfSSimon Glass
698a91194bSMario Six bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
708a91194bSMario Six if (!bus)
718a91194bSMario Six return NULL;
728a91194bSMario Six
73ae242cbfSSimon Glass /* Allocate space if needed (not used by sf-uclass */
74ae242cbfSSimon Glass flash = calloc(1, sizeof(*flash));
75ae242cbfSSimon Glass if (!flash) {
76ae242cbfSSimon Glass debug("SF: Failed to allocate spi_flash\n");
77898e76c9SJagannadha Sutradharudu Teki return NULL;
78898e76c9SJagannadha Sutradharudu Teki }
79898e76c9SJagannadha Sutradharudu Teki
80bfdb07ebSJagan Teki flash->spi = bus;
81bfdb07ebSJagan Teki if (spi_flash_probe_slave(flash)) {
82ae242cbfSSimon Glass spi_free_slave(bus);
83ae242cbfSSimon Glass free(flash);
84ae242cbfSSimon Glass return NULL;
85ae242cbfSSimon Glass }
86ae242cbfSSimon Glass
87ae242cbfSSimon Glass return flash;
88ae242cbfSSimon Glass }
89ae242cbfSSimon Glass
spi_flash_free(struct spi_flash * flash)90898e76c9SJagannadha Sutradharudu Teki void spi_flash_free(struct spi_flash *flash)
91898e76c9SJagannadha Sutradharudu Teki {
929fe6d871SDaniel Schwierzeck #ifdef CONFIG_SPI_FLASH_MTD
939fe6d871SDaniel Schwierzeck spi_flash_mtd_unregister();
949fe6d871SDaniel Schwierzeck #endif
95898e76c9SJagannadha Sutradharudu Teki spi_free_slave(flash->spi);
96898e76c9SJagannadha Sutradharudu Teki free(flash);
97898e76c9SJagannadha Sutradharudu Teki }
98fbb09918SSimon Glass
99fbb09918SSimon Glass #else /* defined CONFIG_DM_SPI_FLASH */
100fbb09918SSimon Glass
spi_flash_std_read(struct udevice * dev,u32 offset,size_t len,void * buf)101fbb09918SSimon Glass static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
102fbb09918SSimon Glass void *buf)
103fbb09918SSimon Glass {
104e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev);
105f2313133SVignesh R struct mtd_info *mtd = &flash->mtd;
106f2313133SVignesh R size_t retlen;
107fbb09918SSimon Glass
108f2313133SVignesh R return log_ret(mtd->_read(mtd, offset, len, &retlen, buf));
109fbb09918SSimon Glass }
110fbb09918SSimon Glass
spi_flash_std_write(struct udevice * dev,u32 offset,size_t len,const void * buf)111339fd6dcSJagan Teki static int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
112fbb09918SSimon Glass const void *buf)
113fbb09918SSimon Glass {
114e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev);
115f2313133SVignesh R struct mtd_info *mtd = &flash->mtd;
116f2313133SVignesh R size_t retlen;
117fbb09918SSimon Glass
118f2313133SVignesh R return mtd->_write(mtd, offset, len, &retlen, buf);
119fbb09918SSimon Glass }
120fbb09918SSimon Glass
spi_flash_std_erase(struct udevice * dev,u32 offset,size_t len)121339fd6dcSJagan Teki static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
122fbb09918SSimon Glass {
123e564f054SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev);
124f2313133SVignesh R struct mtd_info *mtd = &flash->mtd;
125f2313133SVignesh R struct erase_info instr;
126fbb09918SSimon Glass
127f2313133SVignesh R if (offset % mtd->erasesize || len % mtd->erasesize) {
128f2313133SVignesh R printf("SF: Erase offset/length not multiple of erase size\n");
129f2313133SVignesh R return -EINVAL;
130f2313133SVignesh R }
131f2313133SVignesh R
132f2313133SVignesh R memset(&instr, 0, sizeof(instr));
133f2313133SVignesh R instr.addr = offset;
134f2313133SVignesh R instr.len = len;
135f2313133SVignesh R
136f2313133SVignesh R return mtd->_erase(mtd, &instr);
137fbb09918SSimon Glass }
138fbb09918SSimon Glass
spi_flash_std_get_sw_write_prot(struct udevice * dev)139b6e92505SSimon Glass static int spi_flash_std_get_sw_write_prot(struct udevice *dev)
140b6e92505SSimon Glass {
141b6e92505SSimon Glass struct spi_flash *flash = dev_get_uclass_priv(dev);
142b6e92505SSimon Glass
143b6e92505SSimon Glass return spi_flash_cmd_get_sw_write_prot(flash);
144b6e92505SSimon Glass }
145b6e92505SSimon Glass
spi_flash_std_bind(struct udevice * udev)146a5ce032fSJason Zhu static int spi_flash_std_bind(struct udevice *udev)
147a5ce032fSJason Zhu {
148a5ce032fSJason Zhu int ret = 0;
149a5ce032fSJason Zhu
150a5ce032fSJason Zhu #ifdef CONFIG_MTD_BLK
151a5ce032fSJason Zhu struct udevice *bdev;
152a5ce032fSJason Zhu
153a5ce032fSJason Zhu ret = blk_create_devicef(udev, "mtd_blk", "blk", IF_TYPE_MTD,
154a5ce032fSJason Zhu BLK_MTD_SPI_NOR, 512, 0, &bdev);
155a5ce032fSJason Zhu if (ret)
156a5ce032fSJason Zhu printf("Cannot create block device\n");
157a5ce032fSJason Zhu #endif
158a5ce032fSJason Zhu return ret;
159a5ce032fSJason Zhu }
160a5ce032fSJason Zhu
spi_flash_std_probe(struct udevice * dev)161339fd6dcSJagan Teki static int spi_flash_std_probe(struct udevice *dev)
162fbb09918SSimon Glass {
163bcbe3d15SSimon Glass struct spi_slave *slave = dev_get_parent_priv(dev);
164d0cff03eSSimon Glass struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
165fbb09918SSimon Glass struct spi_flash *flash;
166fbb09918SSimon Glass
167e564f054SSimon Glass flash = dev_get_uclass_priv(dev);
168fbb09918SSimon Glass flash->dev = dev;
169bfdb07ebSJagan Teki flash->spi = slave;
170d0cff03eSSimon Glass debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs);
171bfdb07ebSJagan Teki return spi_flash_probe_slave(flash);
172fbb09918SSimon Glass }
173fbb09918SSimon Glass
spi_flash_std_remove(struct udevice * dev)1742233bdccSBoris Brezillon static int spi_flash_std_remove(struct udevice *dev)
1752233bdccSBoris Brezillon {
1762233bdccSBoris Brezillon #ifdef CONFIG_SPI_FLASH_MTD
1772233bdccSBoris Brezillon spi_flash_mtd_unregister();
1782233bdccSBoris Brezillon #endif
1792233bdccSBoris Brezillon return 0;
1802233bdccSBoris Brezillon }
1812233bdccSBoris Brezillon
182fbb09918SSimon Glass static const struct dm_spi_flash_ops spi_flash_std_ops = {
183fbb09918SSimon Glass .read = spi_flash_std_read,
184fbb09918SSimon Glass .write = spi_flash_std_write,
185fbb09918SSimon Glass .erase = spi_flash_std_erase,
186b6e92505SSimon Glass .get_sw_write_prot = spi_flash_std_get_sw_write_prot,
187fbb09918SSimon Glass };
188fbb09918SSimon Glass
189fbb09918SSimon Glass static const struct udevice_id spi_flash_std_ids[] = {
190a1e428c2SVignesh R { .compatible = "jedec,spi-nor" },
191fbb09918SSimon Glass { }
192fbb09918SSimon Glass };
193fbb09918SSimon Glass
194fbb09918SSimon Glass U_BOOT_DRIVER(spi_flash_std) = {
195fbb09918SSimon Glass .name = "spi_flash_std",
196fbb09918SSimon Glass .id = UCLASS_SPI_FLASH,
197fbb09918SSimon Glass .of_match = spi_flash_std_ids,
198a5ce032fSJason Zhu .bind = spi_flash_std_bind,
199fbb09918SSimon Glass .probe = spi_flash_std_probe,
2002233bdccSBoris Brezillon .remove = spi_flash_std_remove,
201fbb09918SSimon Glass .priv_auto_alloc_size = sizeof(struct spi_flash),
202fbb09918SSimon Glass .ops = &spi_flash_std_ops,
203fbb09918SSimon Glass };
204fbb09918SSimon Glass
205fbb09918SSimon Glass #endif /* CONFIG_DM_SPI_FLASH */
206