xref: /openbmc/hiomapd/mtd/backend.c (revision 68a24c9ea5ce11c87fab22a3f4648c7d88c98fee)
1f1e547c7SEvan Lojewski // SPDX-License-Identifier: Apache-2.0
2f1e547c7SEvan Lojewski // Copyright (C) 2018 IBM Corp.
3f1e547c7SEvan Lojewski 
4f1e547c7SEvan Lojewski #define _GNU_SOURCE
5f1e547c7SEvan Lojewski #include <assert.h>
6f1e547c7SEvan Lojewski #include <errno.h>
7f1e547c7SEvan Lojewski #include <fcntl.h>
8f1e547c7SEvan Lojewski #include <getopt.h>
9f1e547c7SEvan Lojewski #include <inttypes.h>
10f1e547c7SEvan Lojewski #include <limits.h>
11f1e547c7SEvan Lojewski #include <mtd/mtd-abi.h>
12f1e547c7SEvan Lojewski #include <poll.h>
13f1e547c7SEvan Lojewski #include <signal.h>
14f1e547c7SEvan Lojewski #include <stdbool.h>
15f1e547c7SEvan Lojewski #include <stdint.h>
16f1e547c7SEvan Lojewski #include <stdio.h>
17f1e547c7SEvan Lojewski #include <stdlib.h>
18f1e547c7SEvan Lojewski #include <string.h>
19f1e547c7SEvan Lojewski #include <sys/ioctl.h>
20f1e547c7SEvan Lojewski #include <sys/mman.h>
21f1e547c7SEvan Lojewski #include <sys/stat.h>
22f1e547c7SEvan Lojewski #include <sys/timerfd.h>
23f1e547c7SEvan Lojewski #include <sys/types.h>
24f1e547c7SEvan Lojewski #include <syslog.h>
25f1e547c7SEvan Lojewski #include <time.h>
26f1e547c7SEvan Lojewski #include <unistd.h>
27f1e547c7SEvan Lojewski 
28f1e547c7SEvan Lojewski #include "common.h"
29f1e547c7SEvan Lojewski #include "backend.h"
30f1e547c7SEvan Lojewski #include "lpc.h"
31f1e547c7SEvan Lojewski #include "mboxd.h"
32f1e547c7SEvan Lojewski #include "mtd/backend.h"
33f1e547c7SEvan Lojewski 
34*68a24c9eSPatrick Williams #pragma GCC diagnostic push
35*68a24c9eSPatrick Williams #pragma GCC diagnostic ignored "-Wpointer-arith"
36*68a24c9eSPatrick Williams 
mtd_dev_init(struct backend * backend,void * data)37f1e547c7SEvan Lojewski static int mtd_dev_init(struct backend *backend, void *data)
38f1e547c7SEvan Lojewski {
39f1e547c7SEvan Lojewski 	const char *path = data;
40f1e547c7SEvan Lojewski 	struct mtd_data *priv;
41f1e547c7SEvan Lojewski 	int rc = 0;
42f1e547c7SEvan Lojewski 
43f1e547c7SEvan Lojewski 	if (!path) {
44f1e547c7SEvan Lojewski 		MSG_INFO("Discovering PNOR MTD\n");
45f1e547c7SEvan Lojewski 		path = get_dev_mtd();
46f1e547c7SEvan Lojewski 	}
47f1e547c7SEvan Lojewski 
48f1e547c7SEvan Lojewski 	priv = malloc(sizeof(*priv));
49f1e547c7SEvan Lojewski 	if (!priv) {
50f1e547c7SEvan Lojewski 		rc = -errno;
51f1e547c7SEvan Lojewski 		goto out;
52f1e547c7SEvan Lojewski 	}
53f1e547c7SEvan Lojewski 
54f1e547c7SEvan Lojewski 	MSG_DBG("Opening %s\n", path);
55f1e547c7SEvan Lojewski 
56f1e547c7SEvan Lojewski 	priv->fd = open(path, O_RDWR);
57f1e547c7SEvan Lojewski 	if (priv->fd < 0) {
58f1e547c7SEvan Lojewski 		MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", path,
59f1e547c7SEvan Lojewski 			strerror(errno));
60f1e547c7SEvan Lojewski 		rc = -errno;
61f1e547c7SEvan Lojewski 		goto cleanup_priv;
62f1e547c7SEvan Lojewski 	}
63f1e547c7SEvan Lojewski 
64f1e547c7SEvan Lojewski 	/* If the file does not support MEMGETINFO it's not an mtd device */
65f1e547c7SEvan Lojewski 	if (ioctl(priv->fd, MEMGETINFO, &priv->mtd_info) == -1) {
66f1e547c7SEvan Lojewski 		rc = -errno;
67f1e547c7SEvan Lojewski 		close(priv->fd);
68f1e547c7SEvan Lojewski 		goto cleanup_priv;
69f1e547c7SEvan Lojewski 	}
70f1e547c7SEvan Lojewski 
71f1e547c7SEvan Lojewski 	if (backend->flash_size == 0) {
72f1e547c7SEvan Lojewski 		/*
73f1e547c7SEvan Lojewski 		 * PNOR images for current OpenPOWER systems are at most 64MB
74f1e547c7SEvan Lojewski 		 * despite the PNOR itself sometimes being as big as 128MB. To
75f1e547c7SEvan Lojewski 		 * ensure the image read from the PNOR is exposed in the LPC
76f1e547c7SEvan Lojewski 		 * address space at the location expected by the host firmware,
77f1e547c7SEvan Lojewski 		 * it is required that the image size be used for
78f1e547c7SEvan Lojewski 		 * context->flash_size, and not the size of the flash device.
79f1e547c7SEvan Lojewski 		 *
80f1e547c7SEvan Lojewski 		 * However, the test cases specify the flash size via special
81f1e547c7SEvan Lojewski 		 * test APIs (controlling flash behaviour) which don't have
82f1e547c7SEvan Lojewski 		 * access to the mbox context. Rather than requiring
83f1e547c7SEvan Lojewski 		 * error-prone assignments in every test case, we instead rely
84f1e547c7SEvan Lojewski 		 * on context->flash_size being set to the size reported by the
85f1e547c7SEvan Lojewski 		 * MEMINFO ioctl().
86f1e547c7SEvan Lojewski 		 *
87f1e547c7SEvan Lojewski 		 * As this case should never be hit in production (i.e. outside
88f1e547c7SEvan Lojewski 		 * the test environment), log an error. As a consequence, this
89f1e547c7SEvan Lojewski 		 * error is expected in the test case output.
90f1e547c7SEvan Lojewski 		 */
91f1e547c7SEvan Lojewski 		MSG_ERR(
92f1e547c7SEvan Lojewski 		    "Flash size MUST be supplied on the commandline. However, "
93f1e547c7SEvan Lojewski 		    "continuing by assuming flash is %u bytes\n",
94f1e547c7SEvan Lojewski 		    priv->mtd_info.size);
95f1e547c7SEvan Lojewski 		backend->flash_size = priv->mtd_info.size;
96f1e547c7SEvan Lojewski 	}
97f1e547c7SEvan Lojewski 
98f1e547c7SEvan Lojewski 	/* We know the erase size so we can allocate the flash_erased bytemap */
99f1e547c7SEvan Lojewski 	backend->erase_size_shift = log_2(priv->mtd_info.erasesize);
100f1e547c7SEvan Lojewski 	backend->block_size_shift = backend->erase_size_shift;
101f1e547c7SEvan Lojewski 	priv->flash_bmap = calloc(backend->flash_size
102f1e547c7SEvan Lojewski 			>> backend->erase_size_shift,
103f1e547c7SEvan Lojewski 		   sizeof(*priv->flash_bmap));
104f1e547c7SEvan Lojewski 	MSG_DBG("Flash erase size: 0x%.8x\n", priv->mtd_info.erasesize);
105f1e547c7SEvan Lojewski 
106f1e547c7SEvan Lojewski 	backend->priv = priv;
107f1e547c7SEvan Lojewski 
108f1e547c7SEvan Lojewski out:
109f1e547c7SEvan Lojewski 	return rc;
110f1e547c7SEvan Lojewski 
111f1e547c7SEvan Lojewski cleanup_priv:
112f1e547c7SEvan Lojewski 	free(priv);
113f1e547c7SEvan Lojewski 	return rc;
114f1e547c7SEvan Lojewski }
115f1e547c7SEvan Lojewski 
mtd_dev_free(struct backend * backend)116f1e547c7SEvan Lojewski static void mtd_dev_free(struct backend *backend)
117f1e547c7SEvan Lojewski {
118f1e547c7SEvan Lojewski 	struct mtd_data *priv = backend->priv;
119f1e547c7SEvan Lojewski 
120f1e547c7SEvan Lojewski 	free(priv->flash_bmap);
121f1e547c7SEvan Lojewski 	close(priv->fd);
122f1e547c7SEvan Lojewski 	free(priv);
123f1e547c7SEvan Lojewski }
124f1e547c7SEvan Lojewski 
125f1e547c7SEvan Lojewski /* Flash Functions */
126f1e547c7SEvan Lojewski 
flash_validate(struct mbox_context * context,uint32_t offset,uint32_t size,bool ro)127*68a24c9eSPatrick Williams int flash_validate(struct mbox_context *context __attribute__((unused)),
128*68a24c9eSPatrick Williams 		   uint32_t offset __attribute__((unused)),
129*68a24c9eSPatrick Williams 		   uint32_t size __attribute__((unused)),
130*68a24c9eSPatrick Williams 		   bool ro __attribute__((unused)))
131f1e547c7SEvan Lojewski {
132f1e547c7SEvan Lojewski 	/* Default behaviour is all accesses are valid */
133f1e547c7SEvan Lojewski 	return 0;
134f1e547c7SEvan Lojewski }
135f1e547c7SEvan Lojewski 
136f1e547c7SEvan Lojewski /*
137f1e547c7SEvan Lojewski  * mtd_is_erased() - Check if an offset into flash is erased
138f1e547c7SEvan Lojewski  * @context:	The mbox context pointer
139f1e547c7SEvan Lojewski  * @offset:	The flash offset to check (bytes)
140f1e547c7SEvan Lojewski  *
141f1e547c7SEvan Lojewski  * Return:	true if erased otherwise false
142f1e547c7SEvan Lojewski  */
mtd_is_erased(struct backend * backend,uint32_t offset)143f1e547c7SEvan Lojewski static inline bool mtd_is_erased(struct backend *backend, uint32_t offset)
144f1e547c7SEvan Lojewski {
145f1e547c7SEvan Lojewski 	const off_t index = offset >> backend->erase_size_shift;
146f1e547c7SEvan Lojewski 	struct mtd_data *priv = backend->priv;
147f1e547c7SEvan Lojewski 
148f1e547c7SEvan Lojewski 	return priv->flash_bmap[index] == FLASH_ERASED;
149f1e547c7SEvan Lojewski }
150f1e547c7SEvan Lojewski 
151f1e547c7SEvan Lojewski /*
152f1e547c7SEvan Lojewski  * mtd_set_bytemap() - Set the flash erased bytemap
153f1e547c7SEvan Lojewski  * @context:	The backend context pointer
154f1e547c7SEvan Lojewski  * @offset:	The flash offset to set (bytes)
155f1e547c7SEvan Lojewski  * @count:	Number of bytes to set
156f1e547c7SEvan Lojewski  * @val:	Value to set the bytemap to
157f1e547c7SEvan Lojewski  *
158f1e547c7SEvan Lojewski  * The flash bytemap only tracks the erased status at the erase block level so
159f1e547c7SEvan Lojewski  * this will update the erased state for an (or many) erase blocks
160f1e547c7SEvan Lojewski  *
161f1e547c7SEvan Lojewski  * Return:	0 if success otherwise negative error code
162f1e547c7SEvan Lojewski  */
mtd_set_bytemap(struct backend * backend,uint32_t offset,uint32_t count,uint8_t val)163f1e547c7SEvan Lojewski static int mtd_set_bytemap(struct backend *backend, uint32_t offset,
164f1e547c7SEvan Lojewski 			   uint32_t count, uint8_t val)
165f1e547c7SEvan Lojewski {
166f1e547c7SEvan Lojewski 	struct mtd_data *priv = backend->priv;
167f1e547c7SEvan Lojewski 
168f1e547c7SEvan Lojewski 	if ((offset + count) > backend->flash_size) {
169f1e547c7SEvan Lojewski 		return -EINVAL;
170f1e547c7SEvan Lojewski 	}
171f1e547c7SEvan Lojewski 
172f1e547c7SEvan Lojewski 	MSG_DBG("Set flash bytemap @ 0x%.8x for 0x%.8x to %s\n", offset, count,
173f1e547c7SEvan Lojewski 		val ? "ERASED" : "DIRTY");
174f1e547c7SEvan Lojewski 	memset(priv->flash_bmap + (offset >> backend->erase_size_shift),
175f1e547c7SEvan Lojewski 	       val,
176f1e547c7SEvan Lojewski 	       align_up(count, 1 << backend->erase_size_shift) >>
177f1e547c7SEvan Lojewski 		   backend->erase_size_shift);
178f1e547c7SEvan Lojewski 
179f1e547c7SEvan Lojewski 	return 0;
180f1e547c7SEvan Lojewski }
181f1e547c7SEvan Lojewski 
182f1e547c7SEvan Lojewski /*
183f1e547c7SEvan Lojewski  * mtd_erase() - Erase the flash
184f1e547c7SEvan Lojewski  * @context:	The mbox context pointer
185f1e547c7SEvan Lojewski  * @offset:	The flash offset to erase (bytes)
186f1e547c7SEvan Lojewski  * @size:	The number of bytes to erase
187f1e547c7SEvan Lojewski  *
188f1e547c7SEvan Lojewski  * Return:	0 on success otherwise negative error code
189f1e547c7SEvan Lojewski  */
mtd_erase(struct backend * backend,uint32_t offset,uint32_t count)190f1e547c7SEvan Lojewski static int mtd_erase(struct backend *backend, uint32_t offset, uint32_t count)
191f1e547c7SEvan Lojewski {
192f1e547c7SEvan Lojewski 	const uint32_t erase_size = 1 << backend->erase_size_shift;
193f1e547c7SEvan Lojewski 	struct mtd_data *priv = backend->priv;
194f1e547c7SEvan Lojewski 	struct erase_info_user erase_info = {0};
195f1e547c7SEvan Lojewski 	int rc;
196f1e547c7SEvan Lojewski 
197f1e547c7SEvan Lojewski 	MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", offset, count);
198f1e547c7SEvan Lojewski 
199f1e547c7SEvan Lojewski 	/*
200f1e547c7SEvan Lojewski 	 * We have an erased_bytemap for the flash so we want to avoid erasing
201f1e547c7SEvan Lojewski 	 * blocks which we already know to be erased. Look for runs of blocks
202f1e547c7SEvan Lojewski 	 * which aren't erased and erase the entire run at once to avoid how
203f1e547c7SEvan Lojewski 	 * often we have to call the erase ioctl. If the block is already
204f1e547c7SEvan Lojewski 	 * erased then there's nothing we need to do.
205f1e547c7SEvan Lojewski 	 */
206f1e547c7SEvan Lojewski 	while (count) {
207f1e547c7SEvan Lojewski 		if (!mtd_is_erased(backend, offset)) { /* Need to erase */
208f1e547c7SEvan Lojewski 			if (!erase_info.length) { /* Start of not-erased run */
209f1e547c7SEvan Lojewski 				erase_info.start = offset;
210f1e547c7SEvan Lojewski 			}
211f1e547c7SEvan Lojewski 			erase_info.length += erase_size;
212f1e547c7SEvan Lojewski 		} else if (erase_info.length) { /* Already erased|end of run? */
213f1e547c7SEvan Lojewski 			/* Erase the previous run which just ended */
214f1e547c7SEvan Lojewski 			MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
215f1e547c7SEvan Lojewski 				erase_info.start, erase_info.length);
216f1e547c7SEvan Lojewski 			rc = ioctl(priv->fd, MEMERASE, &erase_info);
217f1e547c7SEvan Lojewski 			if (rc < 0) {
218f1e547c7SEvan Lojewski 				MSG_ERR("Couldn't erase flash at 0x%.8x\n",
219f1e547c7SEvan Lojewski 					erase_info.start);
220f1e547c7SEvan Lojewski 				return -errno;
221f1e547c7SEvan Lojewski 			}
222f1e547c7SEvan Lojewski 			/* Mark ERASED where we just erased */
223f1e547c7SEvan Lojewski 			mtd_set_bytemap(backend, erase_info.start,
224f1e547c7SEvan Lojewski 					erase_info.length, FLASH_ERASED);
225f1e547c7SEvan Lojewski 			erase_info.start = 0;
226f1e547c7SEvan Lojewski 			erase_info.length = 0;
227f1e547c7SEvan Lojewski 		}
228f1e547c7SEvan Lojewski 
229f1e547c7SEvan Lojewski 		offset += erase_size;
230f1e547c7SEvan Lojewski 		count -= erase_size;
231f1e547c7SEvan Lojewski 	}
232f1e547c7SEvan Lojewski 
233f1e547c7SEvan Lojewski 	if (erase_info.length) {
234f1e547c7SEvan Lojewski 		MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", erase_info.start,
235f1e547c7SEvan Lojewski 			erase_info.length);
236f1e547c7SEvan Lojewski 		rc = ioctl(priv->fd, MEMERASE, &erase_info);
237f1e547c7SEvan Lojewski 		if (rc < 0) {
238f1e547c7SEvan Lojewski 			MSG_ERR("Couldn't erase flash at 0x%.8x\n",
239f1e547c7SEvan Lojewski 				erase_info.start);
240f1e547c7SEvan Lojewski 			return -errno;
241f1e547c7SEvan Lojewski 		}
242f1e547c7SEvan Lojewski 		/* Mark ERASED where we just erased */
243f1e547c7SEvan Lojewski 		mtd_set_bytemap(backend, erase_info.start, erase_info.length,
244f1e547c7SEvan Lojewski 				FLASH_ERASED);
245f1e547c7SEvan Lojewski 	}
246f1e547c7SEvan Lojewski 
247f1e547c7SEvan Lojewski 	return 0;
248f1e547c7SEvan Lojewski }
249f1e547c7SEvan Lojewski 
250f1e547c7SEvan Lojewski #define CHUNKSIZE (64 * 1024)
251f1e547c7SEvan Lojewski 
252f1e547c7SEvan Lojewski /*
253f1e547c7SEvan Lojewski  * mtd_copy() - Copy data from the flash device into a provided buffer
254f1e547c7SEvan Lojewski  * @context:	The backend context pointer
255f1e547c7SEvan Lojewski  * @offset:	The flash offset to copy from (bytes)
256f1e547c7SEvan Lojewski  * @mem:	The buffer to copy into (must be of atleast 'size' bytes)
257f1e547c7SEvan Lojewski  * @size:	The number of bytes to copy
258f1e547c7SEvan Lojewski  * Return:	Number of bytes copied on success, otherwise negative error
259f1e547c7SEvan Lojewski  *		code. mtd_copy will copy at most 'size' bytes, but it may
260f1e547c7SEvan Lojewski  *		copy less.
261f1e547c7SEvan Lojewski  */
mtd_copy(struct backend * backend,uint32_t offset,void * mem,uint32_t size)262f1e547c7SEvan Lojewski static int64_t mtd_copy(struct backend *backend, uint32_t offset,
263f1e547c7SEvan Lojewski 			  void *mem, uint32_t size)
264f1e547c7SEvan Lojewski {
265f1e547c7SEvan Lojewski 	struct mtd_data *priv = backend->priv;
266f1e547c7SEvan Lojewski 	int32_t size_read;
267f1e547c7SEvan Lojewski 	void *start = mem;
268f1e547c7SEvan Lojewski 
269f1e547c7SEvan Lojewski 	MSG_DBG("Copy flash to %p for size 0x%.8x from offset 0x%.8x\n", mem,
270f1e547c7SEvan Lojewski 		size, offset);
271f1e547c7SEvan Lojewski 	if (lseek(priv->fd, offset, SEEK_SET) != offset) {
272f1e547c7SEvan Lojewski 		MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset,
273f1e547c7SEvan Lojewski 			strerror(errno));
274f1e547c7SEvan Lojewski 		return -errno;
275f1e547c7SEvan Lojewski 	}
276f1e547c7SEvan Lojewski 
277f1e547c7SEvan Lojewski 	do {
278f1e547c7SEvan Lojewski 		size_read = read(priv->fd, mem,
279f1e547c7SEvan Lojewski 				 min_u32(CHUNKSIZE, size));
280f1e547c7SEvan Lojewski 		if (size_read < 0) {
281f1e547c7SEvan Lojewski 			MSG_ERR("Couldn't copy mtd into ram: %s\n",
282f1e547c7SEvan Lojewski 				strerror(errno));
283f1e547c7SEvan Lojewski 			return -errno;
284f1e547c7SEvan Lojewski 		}
285f1e547c7SEvan Lojewski 
286f1e547c7SEvan Lojewski 		size -= size_read;
287f1e547c7SEvan Lojewski 		mem += size_read;
288f1e547c7SEvan Lojewski 	} while (size && size_read);
289f1e547c7SEvan Lojewski 
290f1e547c7SEvan Lojewski 	return size_read ? mem - start : -EIO;
291f1e547c7SEvan Lojewski }
292f1e547c7SEvan Lojewski 
293f1e547c7SEvan Lojewski /*
294f1e547c7SEvan Lojewski  * mtd_write() - Write the flash from a provided buffer
295f1e547c7SEvan Lojewski  * @context:	The mbox context pointer
296f1e547c7SEvan Lojewski  * @offset:	The flash offset to write to (bytes)
297f1e547c7SEvan Lojewski  * @buf:	The buffer to write from (must be of atleast size)
298f1e547c7SEvan Lojewski  * @size:	The number of bytes to write
299f1e547c7SEvan Lojewski  *
300f1e547c7SEvan Lojewski  * Return:	0 on success otherwise negative error code
301f1e547c7SEvan Lojewski  */
mtd_write(struct backend * backend,uint32_t offset,void * buf,uint32_t count)302f1e547c7SEvan Lojewski static int mtd_write(struct backend *backend, uint32_t offset, void *buf,
303f1e547c7SEvan Lojewski 		       uint32_t count)
304f1e547c7SEvan Lojewski {
305f1e547c7SEvan Lojewski 	struct mtd_data *priv = backend->priv;
306f1e547c7SEvan Lojewski 	uint32_t buf_offset = 0;
307f1e547c7SEvan Lojewski 	int rc;
308f1e547c7SEvan Lojewski 
309f1e547c7SEvan Lojewski 	MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count,
310f1e547c7SEvan Lojewski 		buf);
311f1e547c7SEvan Lojewski 
312f1e547c7SEvan Lojewski 	if (lseek(priv->fd, offset, SEEK_SET) != offset) {
313f1e547c7SEvan Lojewski 		MSG_ERR("Couldn't seek flash at pos: %u %s\n", offset,
314f1e547c7SEvan Lojewski 			strerror(errno));
315f1e547c7SEvan Lojewski 		return -errno;
316f1e547c7SEvan Lojewski 	}
317f1e547c7SEvan Lojewski 
318f1e547c7SEvan Lojewski 	while (count) {
319f1e547c7SEvan Lojewski 		rc = write(priv->fd, buf + buf_offset, count);
320f1e547c7SEvan Lojewski 		if (rc < 0) {
321f1e547c7SEvan Lojewski 			MSG_ERR("Couldn't write to flash, write lost: %s\n",
322f1e547c7SEvan Lojewski 				strerror(errno));
323f1e547c7SEvan Lojewski 			return -errno;
324f1e547c7SEvan Lojewski 		}
325f1e547c7SEvan Lojewski 		/* Mark *NOT* erased where we just wrote */
326f1e547c7SEvan Lojewski 		mtd_set_bytemap(backend, offset + buf_offset, rc, FLASH_DIRTY);
327f1e547c7SEvan Lojewski 		count -= rc;
328f1e547c7SEvan Lojewski 		buf_offset += rc;
329f1e547c7SEvan Lojewski 	}
330f1e547c7SEvan Lojewski 
331f1e547c7SEvan Lojewski 	return 0;
332f1e547c7SEvan Lojewski }
333f1e547c7SEvan Lojewski 
334f1e547c7SEvan Lojewski /*
335f1e547c7SEvan Lojewski  * mtd_reset() - Reset the lpc bus mapping
336f1e547c7SEvan Lojewski  * @context:    The mbox context pointer
337f1e547c7SEvan Lojewski  *
338f1e547c7SEvan Lojewski  * Return:      A value from enum backend_reset_mode, otherwise a negative
339f1e547c7SEvan Lojewski  *		error code
340f1e547c7SEvan Lojewski  */
mtd_reset(struct backend * backend,void * buf,uint32_t count)341*68a24c9eSPatrick Williams static int mtd_reset(struct backend *backend __attribute__((unused)),
342f1e547c7SEvan Lojewski 		     void *buf __attribute__((unused)),
343f1e547c7SEvan Lojewski 		     uint32_t count __attribute__((unused)))
344f1e547c7SEvan Lojewski {
345f1e547c7SEvan Lojewski 	return reset_lpc_flash;
346f1e547c7SEvan Lojewski }
347f1e547c7SEvan Lojewski 
348f1e547c7SEvan Lojewski static const struct backend_ops mtd_ops = {
349f1e547c7SEvan Lojewski 	.init = mtd_dev_init,
350f1e547c7SEvan Lojewski 	.free = mtd_dev_free,
351f1e547c7SEvan Lojewski 	.copy = mtd_copy,
352f1e547c7SEvan Lojewski 	.set_bytemap = mtd_set_bytemap,
353f1e547c7SEvan Lojewski 	.erase = mtd_erase,
354f1e547c7SEvan Lojewski 	.write = mtd_write,
355f1e547c7SEvan Lojewski 	.validate = NULL,
356f1e547c7SEvan Lojewski 	.reset = mtd_reset,
3578cef63e3SAlvin Wang 	.align_offset = NULL,
358f1e547c7SEvan Lojewski };
359f1e547c7SEvan Lojewski 
backend_get_mtd(void)360f1e547c7SEvan Lojewski struct backend backend_get_mtd(void)
361f1e547c7SEvan Lojewski {
362f1e547c7SEvan Lojewski 	struct backend be = {0};
363f1e547c7SEvan Lojewski 
364f1e547c7SEvan Lojewski 	be.ops = &mtd_ops;
365f1e547c7SEvan Lojewski 
366f1e547c7SEvan Lojewski 	return be;
367f1e547c7SEvan Lojewski }
368f1e547c7SEvan Lojewski 
backend_probe_mtd(struct backend * master,const char * path)369f1e547c7SEvan Lojewski int backend_probe_mtd(struct backend *master, const char *path)
370f1e547c7SEvan Lojewski {
371f1e547c7SEvan Lojewski 	struct backend with;
372f1e547c7SEvan Lojewski 
373f1e547c7SEvan Lojewski 	assert(master);
374f1e547c7SEvan Lojewski 	with = backend_get_mtd();
375f1e547c7SEvan Lojewski 
376f1e547c7SEvan Lojewski 	return backend_init(master, &with, (void *)path);
377f1e547c7SEvan Lojewski }
378*68a24c9eSPatrick Williams 
379*68a24c9eSPatrick Williams #pragma GCC diagnostic pop
380