blob: 04de8680809c055206b14bb34c736ec5cfde20a0 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +02002/*
3 * Copyright (C) 2012-2014 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +02004 */
5
6#include <common.h>
Simon Glassb79fdc72020-05-10 11:39:54 -06007#include <flash.h>
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +02008#include <malloc.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +09009#include <linux/errno.h>
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +020010#include <linux/mtd/mtd.h>
11#include <spi_flash.h>
12
Marek Behúnb7f06052021-05-26 14:08:20 +020013#if CONFIG_IS_ENABLED(DM_SPI_FLASH)
14
15int spi_flash_mtd_register(struct spi_flash *flash)
16{
17 return add_mtd_device(&flash->mtd);
18}
19
20void spi_flash_mtd_unregister(struct spi_flash *flash)
21{
22 del_mtd_device(&flash->mtd);
23}
24
25#else /* !CONFIG_IS_ENABLED(DM_SPI_FLASH) */
26
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +020027static struct mtd_info sf_mtd_info;
Boris Brezillon492151b2018-12-02 10:54:25 +010028static bool sf_mtd_registered;
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +020029static char sf_mtd_name[8];
30
31static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
32{
33 struct spi_flash *flash = mtd->priv;
34 int err;
35
Boris Brezillon08898e82018-12-02 10:54:32 +010036 if (!flash)
37 return -ENODEV;
38
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +020039 instr->state = MTD_ERASING;
40
41 err = spi_flash_erase(flash, instr->addr, instr->len);
42 if (err) {
43 instr->state = MTD_ERASE_FAILED;
44 instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
45 return -EIO;
46 }
47
48 instr->state = MTD_ERASE_DONE;
49 mtd_erase_callback(instr);
50
51 return 0;
52}
53
54static int spi_flash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
55 size_t *retlen, u_char *buf)
56{
57 struct spi_flash *flash = mtd->priv;
58 int err;
59
Boris Brezillon08898e82018-12-02 10:54:32 +010060 if (!flash)
61 return -ENODEV;
62
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +020063 err = spi_flash_read(flash, from, len, buf);
64 if (!err)
65 *retlen = len;
66
67 return err;
68}
69
70static int spi_flash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
71 size_t *retlen, const u_char *buf)
72{
73 struct spi_flash *flash = mtd->priv;
74 int err;
75
Boris Brezillon08898e82018-12-02 10:54:32 +010076 if (!flash)
77 return -ENODEV;
78
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +020079 err = spi_flash_write(flash, to, len, buf);
80 if (!err)
81 *retlen = len;
82
83 return err;
84}
85
86static void spi_flash_mtd_sync(struct mtd_info *mtd)
87{
88}
89
90static int spi_flash_mtd_number(void)
91{
92#ifdef CONFIG_SYS_MAX_FLASH_BANKS
93 return CONFIG_SYS_MAX_FLASH_BANKS;
94#else
95 return 0;
96#endif
97}
98
99int spi_flash_mtd_register(struct spi_flash *flash)
100{
Boris Brezillon492151b2018-12-02 10:54:25 +0100101 int ret;
102
Boris Brezillon08898e82018-12-02 10:54:32 +0100103 if (sf_mtd_registered) {
104 ret = del_mtd_device(&sf_mtd_info);
105 if (ret)
106 return ret;
107
108 sf_mtd_registered = false;
109 }
Boris Brezillon492151b2018-12-02 10:54:25 +0100110
111 sf_mtd_registered = false;
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +0200112 memset(&sf_mtd_info, 0, sizeof(sf_mtd_info));
113 sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number());
114
115 sf_mtd_info.name = sf_mtd_name;
116 sf_mtd_info.type = MTD_NORFLASH;
117 sf_mtd_info.flags = MTD_CAP_NORFLASH;
118 sf_mtd_info.writesize = 1;
119 sf_mtd_info.writebufsize = flash->page_size;
120
121 sf_mtd_info._erase = spi_flash_mtd_erase;
122 sf_mtd_info._read = spi_flash_mtd_read;
123 sf_mtd_info._write = spi_flash_mtd_write;
124 sf_mtd_info._sync = spi_flash_mtd_sync;
125
126 sf_mtd_info.size = flash->size;
127 sf_mtd_info.priv = flash;
Marek Behún2d1a9a62021-05-26 14:08:21 +0200128 sf_mtd_info.dev = flash->dev;
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +0200129
130 /* Only uniform flash devices for now */
131 sf_mtd_info.numeraseregions = 0;
132 sf_mtd_info.erasesize = flash->sector_size;
133
Boris Brezillon492151b2018-12-02 10:54:25 +0100134 ret = add_mtd_device(&sf_mtd_info);
135 if (!ret)
136 sf_mtd_registered = true;
137
138 return ret;
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +0200139}
140
Marek Behúnb7f06052021-05-26 14:08:20 +0200141void spi_flash_mtd_unregister(struct spi_flash *flash)
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +0200142{
Boris Brezillon08898e82018-12-02 10:54:32 +0100143 int ret;
144
145 if (!sf_mtd_registered)
146 return;
147
148 ret = del_mtd_device(&sf_mtd_info);
149 if (!ret) {
150 sf_mtd_registered = false;
151 return;
152 }
153
154 /*
155 * Setting mtd->priv to NULL is the best we can do. Thanks to that,
156 * the MTD layer can still call mtd hooks without risking a
157 * use-after-free bug. Still, things should be fixed to prevent the
158 * spi_flash object from being destroyed when del_mtd_device() fails.
159 */
160 sf_mtd_info.priv = NULL;
161 printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!",
162 sf_mtd_info.name);
Daniel Schwierzeck9fe6d872015-04-27 07:42:04 +0200163}
Marek Behúnb7f06052021-05-26 14:08:20 +0200164
165#endif /* !CONFIG_IS_ENABLED(DM_SPI_FLASH) */