1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 #include <errno.h>
9 
10 #include <zephyr/drivers/flash.h>
11 #include <zephyr/logging/log.h>
12 #include <string.h>
13 
14 LOG_MODULE_REGISTER(flash, CONFIG_FLASH_LOG_LEVEL);
15 
z_impl_flash_fill(const struct device * dev,uint8_t val,off_t offset,size_t size)16 int z_impl_flash_fill(const struct device *dev, uint8_t val, off_t offset,
17 		      size_t size)
18 {
19 	uint8_t filler[CONFIG_FLASH_FILL_BUFFER_SIZE];
20 	const struct flash_driver_api *api =
21 		(const struct flash_driver_api *)dev->api;
22 	const struct flash_parameters *fparams = api->get_parameters(dev);
23 	int rc = 0;
24 	size_t stored = 0;
25 
26 	if (sizeof(filler) < fparams->write_block_size) {
27 		LOG_ERR("Size of CONFIG_FLASH_FILL_BUFFER_SIZE");
28 		return -EINVAL;
29 	}
30 	/* The flash_write will, probably, check write alignment but this
31 	 * is too late, as we write datain chunks; data alignment may be
32 	 * broken by the size of the last chunk, that is why the check
33 	 * happens here too.
34 	 * Note that we have no way to check whether offset and size are
35 	 * are correct, as such info is only available at the level of
36 	 * a driver, so only basic check on offset.
37 	 */
38 	if (offset < 0) {
39 		LOG_ERR("Negative offset not allowed\n");
40 		return -EINVAL;
41 	}
42 	if ((size | (size_t)offset) & (fparams->write_block_size - 1)) {
43 		LOG_ERR("Incorrect size or offset alignment, expected %zx\n",
44 			fparams->write_block_size);
45 		return -EINVAL;
46 	}
47 
48 	memset(filler, val, sizeof(filler));
49 
50 	while (stored < size) {
51 		size_t chunk = MIN(sizeof(filler), size - stored);
52 
53 		rc = api->write(dev, offset + stored, filler, chunk);
54 		if (rc < 0) {
55 			LOG_DBG("Fill to dev %p failed at offset 0x%zx\n",
56 				dev, (size_t)offset + stored);
57 			break;
58 		}
59 		stored += chunk;
60 	}
61 	return rc;
62 }
63 
z_impl_flash_flatten(const struct device * dev,off_t offset,size_t size)64 int z_impl_flash_flatten(const struct device *dev, off_t offset, size_t size)
65 {
66 	const struct flash_driver_api *api =
67 		(const struct flash_driver_api *)dev->api;
68 	__maybe_unused const struct flash_parameters *params = api->get_parameters(dev);
69 
70 #if defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE)
71 	if ((flash_params_get_erase_cap(params) & FLASH_ERASE_C_EXPLICIT) &&
72 		api->erase != NULL) {
73 		return api->erase(dev, offset, size);
74 	}
75 #endif
76 
77 #if defined(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE)
78 	return flash_fill(dev, params->erase_value, offset, size);
79 #else
80 	return -ENOSYS;
81 #endif
82 }
83