blob: 071b25ac67f2d4e14f8ea3cf846716cbe926df85 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +02002/*
3 * Copyright (C) 2012-2014 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +02004 */
5
6#include <common.h>
7#include <malloc.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +09008#include <linux/errno.h>
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +02009#include <linux/mtd/mtd.h>
10#include <spi_flash.h>
11
Marek Behúnc1fcc142021-05-26 14:08:20 +020012#if CONFIG_IS_ENABLED(DM_SPI_FLASH)
13
14int spi_flash_mtd_register(struct spi_flash *flash)
15{
16 return add_mtd_device(&flash->mtd);
17}
18
19void spi_flash_mtd_unregister(struct spi_flash *flash)
20{
21 del_mtd_device(&flash->mtd);
22}
23
24#else /* !CONFIG_IS_ENABLED(DM_SPI_FLASH) */
25
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +020026static struct mtd_info sf_mtd_info;
Boris Brezillon9080e282018-12-02 10:54:25 +010027static bool sf_mtd_registered;
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +020028static char sf_mtd_name[8];
29
30static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
31{
32 struct spi_flash *flash = mtd->priv;
33 int err;
34
Boris Brezillon925a51d2018-12-02 10:54:32 +010035 if (!flash)
36 return -ENODEV;
37
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +020038 instr->state = MTD_ERASING;
39
40 err = spi_flash_erase(flash, instr->addr, instr->len);
41 if (err) {
42 instr->state = MTD_ERASE_FAILED;
43 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
44 return -EIO;
45 }
46
47 instr->state = MTD_ERASE_DONE;
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +020048
49 return 0;
50}
51
52static int spi_flash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
53 size_t *retlen, u_char *buf)
54{
55 struct spi_flash *flash = mtd->priv;
56 int err;
57
Boris Brezillon925a51d2018-12-02 10:54:32 +010058 if (!flash)
59 return -ENODEV;
60
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +020061 err = spi_flash_read(flash, from, len, buf);
62 if (!err)
63 *retlen = len;
64
65 return err;
66}
67
68static int spi_flash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
69 size_t *retlen, const u_char *buf)
70{
71 struct spi_flash *flash = mtd->priv;
72 int err;
73
Boris Brezillon925a51d2018-12-02 10:54:32 +010074 if (!flash)
75 return -ENODEV;
76
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +020077 err = spi_flash_write(flash, to, len, buf);
78 if (!err)
79 *retlen = len;
80
81 return err;
82}
83
84static void spi_flash_mtd_sync(struct mtd_info *mtd)
85{
86}
87
88static int spi_flash_mtd_number(void)
89{
90#ifdef CONFIG_SYS_MAX_FLASH_BANKS
91 return CONFIG_SYS_MAX_FLASH_BANKS;
92#else
93 return 0;
94#endif
95}
96
97int spi_flash_mtd_register(struct spi_flash *flash)
98{
Boris Brezillon9080e282018-12-02 10:54:25 +010099 int ret;
100
Boris Brezillon925a51d2018-12-02 10:54:32 +0100101 if (sf_mtd_registered) {
102 ret = del_mtd_device(&sf_mtd_info);
103 if (ret)
104 return ret;
105
106 sf_mtd_registered = false;
107 }
Boris Brezillon9080e282018-12-02 10:54:25 +0100108
109 sf_mtd_registered = false;
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +0200110 memset(&sf_mtd_info, 0, sizeof(sf_mtd_info));
111 sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number());
112
113 sf_mtd_info.name = sf_mtd_name;
114 sf_mtd_info.type = MTD_NORFLASH;
115 sf_mtd_info.flags = MTD_CAP_NORFLASH;
116 sf_mtd_info.writesize = 1;
117 sf_mtd_info.writebufsize = flash->page_size;
118
119 sf_mtd_info._erase = spi_flash_mtd_erase;
120 sf_mtd_info._read = spi_flash_mtd_read;
121 sf_mtd_info._write = spi_flash_mtd_write;
122 sf_mtd_info._sync = spi_flash_mtd_sync;
123
124 sf_mtd_info.size = flash->size;
125 sf_mtd_info.priv = flash;
Marek Behúnd37eb232021-05-26 14:08:21 +0200126 sf_mtd_info.dev = flash->dev;
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +0200127
128 /* Only uniform flash devices for now */
129 sf_mtd_info.numeraseregions = 0;
130 sf_mtd_info.erasesize = flash->sector_size;
131
Boris Brezillon9080e282018-12-02 10:54:25 +0100132 ret = add_mtd_device(&sf_mtd_info);
133 if (!ret)
134 sf_mtd_registered = true;
135
136 return ret;
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +0200137}
138
Marek Behúnc1fcc142021-05-26 14:08:20 +0200139void spi_flash_mtd_unregister(struct spi_flash *flash)
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +0200140{
Boris Brezillon925a51d2018-12-02 10:54:32 +0100141 int ret;
142
143 if (!sf_mtd_registered)
144 return;
145
146 ret = del_mtd_device(&sf_mtd_info);
147 if (!ret) {
148 sf_mtd_registered = false;
149 return;
150 }
151
152 /*
153 * Setting mtd->priv to NULL is the best we can do. Thanks to that,
154 * the MTD layer can still call mtd hooks without risking a
155 * use-after-free bug. Still, things should be fixed to prevent the
156 * spi_flash object from being destroyed when del_mtd_device() fails.
157 */
158 sf_mtd_info.priv = NULL;
159 printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!",
160 sf_mtd_info.name);
Daniel Schwierzeck06cfc032015-04-27 07:42:04 +0200161}
Marek Behúnc1fcc142021-05-26 14:08:20 +0200162
163#endif /* !CONFIG_IS_ENABLED(DM_SPI_FLASH) */