1b114abb6SLionel Debieve /*
2*6e86b462SYann Gautier * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
3b114abb6SLionel Debieve *
4b114abb6SLionel Debieve * SPDX-License-Identifier: BSD-3-Clause
5b114abb6SLionel Debieve */
6b114abb6SLionel Debieve
7b114abb6SLionel Debieve #include <assert.h>
8b114abb6SLionel Debieve #include <errno.h>
9b114abb6SLionel Debieve #include <string.h>
10b114abb6SLionel Debieve
11b114abb6SLionel Debieve #include <common/debug.h>
12b114abb6SLionel Debieve #include <drivers/io/io_driver.h>
13b114abb6SLionel Debieve #include <drivers/io/io_mtd.h>
14b114abb6SLionel Debieve #include <lib/utils.h>
15b114abb6SLionel Debieve
16*6e86b462SYann Gautier #include <platform_def.h>
17*6e86b462SYann Gautier
18b114abb6SLionel Debieve typedef struct {
19b114abb6SLionel Debieve io_mtd_dev_spec_t *dev_spec;
20b114abb6SLionel Debieve uintptr_t base;
219a9ea829SLionel Debieve unsigned long long pos; /* Offset in bytes */
22b114abb6SLionel Debieve unsigned long long size; /* Size of device in bytes */
239a9ea829SLionel Debieve unsigned long long extra_offset; /* Extra offset in bytes */
24b114abb6SLionel Debieve } mtd_dev_state_t;
25b114abb6SLionel Debieve
26b114abb6SLionel Debieve io_type_t device_type_mtd(void);
27b114abb6SLionel Debieve
28b114abb6SLionel Debieve static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
29b114abb6SLionel Debieve io_entity_t *entity);
30b114abb6SLionel Debieve static int mtd_seek(io_entity_t *entity, int mode, signed long long offset);
31b114abb6SLionel Debieve static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
32b114abb6SLionel Debieve size_t *length_read);
33b114abb6SLionel Debieve static int mtd_close(io_entity_t *entity);
34b114abb6SLionel Debieve static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
35b114abb6SLionel Debieve static int mtd_dev_close(io_dev_info_t *dev_info);
36b114abb6SLionel Debieve
37b114abb6SLionel Debieve static const io_dev_connector_t mtd_dev_connector = {
38b114abb6SLionel Debieve .dev_open = mtd_dev_open
39b114abb6SLionel Debieve };
40b114abb6SLionel Debieve
41b114abb6SLionel Debieve static const io_dev_funcs_t mtd_dev_funcs = {
42b114abb6SLionel Debieve .type = device_type_mtd,
43b114abb6SLionel Debieve .open = mtd_open,
44b114abb6SLionel Debieve .seek = mtd_seek,
45b114abb6SLionel Debieve .read = mtd_read,
46b114abb6SLionel Debieve .close = mtd_close,
47b114abb6SLionel Debieve .dev_close = mtd_dev_close,
48b114abb6SLionel Debieve };
49b114abb6SLionel Debieve
50b114abb6SLionel Debieve static mtd_dev_state_t state_pool[MAX_IO_MTD_DEVICES];
51b114abb6SLionel Debieve static io_dev_info_t dev_info_pool[MAX_IO_MTD_DEVICES];
52b114abb6SLionel Debieve
device_type_mtd(void)53b114abb6SLionel Debieve io_type_t device_type_mtd(void)
54b114abb6SLionel Debieve {
55b114abb6SLionel Debieve return IO_TYPE_MTD;
56b114abb6SLionel Debieve }
57b114abb6SLionel Debieve
58b114abb6SLionel Debieve /* Locate a MTD state in the pool, specified by address */
find_first_mtd_state(const io_mtd_dev_spec_t * dev_spec,unsigned int * index_out)59b114abb6SLionel Debieve static int find_first_mtd_state(const io_mtd_dev_spec_t *dev_spec,
60b114abb6SLionel Debieve unsigned int *index_out)
61b114abb6SLionel Debieve {
62b114abb6SLionel Debieve unsigned int index;
63b114abb6SLionel Debieve int result = -ENOENT;
64b114abb6SLionel Debieve
65b114abb6SLionel Debieve for (index = 0U; index < MAX_IO_MTD_DEVICES; index++) {
66b114abb6SLionel Debieve /* dev_spec is used as identifier since it's unique */
67b114abb6SLionel Debieve if (state_pool[index].dev_spec == dev_spec) {
68b114abb6SLionel Debieve result = 0;
69b114abb6SLionel Debieve *index_out = index;
70b114abb6SLionel Debieve break;
71b114abb6SLionel Debieve }
72b114abb6SLionel Debieve }
73b114abb6SLionel Debieve
74b114abb6SLionel Debieve return result;
75b114abb6SLionel Debieve }
76b114abb6SLionel Debieve
77b114abb6SLionel Debieve /* Allocate a device info from the pool */
allocate_dev_info(io_dev_info_t ** dev_info)78b114abb6SLionel Debieve static int allocate_dev_info(io_dev_info_t **dev_info)
79b114abb6SLionel Debieve {
80b114abb6SLionel Debieve unsigned int index = 0U;
81b114abb6SLionel Debieve int result;
82b114abb6SLionel Debieve
83b114abb6SLionel Debieve result = find_first_mtd_state(NULL, &index);
84b114abb6SLionel Debieve if (result != 0) {
85b114abb6SLionel Debieve return -ENOMEM;
86b114abb6SLionel Debieve }
87b114abb6SLionel Debieve
88b114abb6SLionel Debieve dev_info_pool[index].funcs = &mtd_dev_funcs;
89b114abb6SLionel Debieve dev_info_pool[index].info = (uintptr_t)&state_pool[index];
90b114abb6SLionel Debieve *dev_info = &dev_info_pool[index];
91b114abb6SLionel Debieve
92b114abb6SLionel Debieve return 0;
93b114abb6SLionel Debieve }
94b114abb6SLionel Debieve
95b114abb6SLionel Debieve /* Release a device info from the pool */
free_dev_info(io_dev_info_t * dev_info)96b114abb6SLionel Debieve static int free_dev_info(io_dev_info_t *dev_info)
97b114abb6SLionel Debieve {
98b114abb6SLionel Debieve int result;
99b114abb6SLionel Debieve unsigned int index = 0U;
100b114abb6SLionel Debieve mtd_dev_state_t *state;
101b114abb6SLionel Debieve
102b114abb6SLionel Debieve state = (mtd_dev_state_t *)dev_info->info;
103b114abb6SLionel Debieve result = find_first_mtd_state(state->dev_spec, &index);
104b114abb6SLionel Debieve if (result != 0) {
105b114abb6SLionel Debieve return result;
106b114abb6SLionel Debieve }
107b114abb6SLionel Debieve
108b114abb6SLionel Debieve zeromem(state, sizeof(mtd_dev_state_t));
109b114abb6SLionel Debieve zeromem(dev_info, sizeof(io_dev_info_t));
110b114abb6SLionel Debieve
111b114abb6SLionel Debieve return 0;
112b114abb6SLionel Debieve }
113b114abb6SLionel Debieve
mtd_add_extra_offset(mtd_dev_state_t * cur,size_t * extra_offset)1149a9ea829SLionel Debieve static int mtd_add_extra_offset(mtd_dev_state_t *cur, size_t *extra_offset)
1159a9ea829SLionel Debieve {
1169a9ea829SLionel Debieve io_mtd_ops_t *ops = &cur->dev_spec->ops;
1179a9ea829SLionel Debieve int ret;
1189a9ea829SLionel Debieve
1199a9ea829SLionel Debieve if (ops->seek == NULL) {
1209a9ea829SLionel Debieve return 0;
1219a9ea829SLionel Debieve }
1229a9ea829SLionel Debieve
1239a9ea829SLionel Debieve ret = ops->seek(cur->base, cur->pos, extra_offset);
1249a9ea829SLionel Debieve if (ret != 0) {
1259a9ea829SLionel Debieve ERROR("%s: Seek error %d\n", __func__, ret);
1269a9ea829SLionel Debieve return ret;
1279a9ea829SLionel Debieve }
1289a9ea829SLionel Debieve
1299a9ea829SLionel Debieve return 0;
1309a9ea829SLionel Debieve }
1319a9ea829SLionel Debieve
mtd_open(io_dev_info_t * dev_info,const uintptr_t spec,io_entity_t * entity)132b114abb6SLionel Debieve static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
133b114abb6SLionel Debieve io_entity_t *entity)
134b114abb6SLionel Debieve {
135b114abb6SLionel Debieve mtd_dev_state_t *cur;
1369a9ea829SLionel Debieve io_block_spec_t *region;
1379a9ea829SLionel Debieve size_t extra_offset = 0U;
1389a9ea829SLionel Debieve int ret;
139b114abb6SLionel Debieve
140b114abb6SLionel Debieve assert((dev_info->info != 0UL) && (entity->info == 0UL));
141b114abb6SLionel Debieve
1429a9ea829SLionel Debieve region = (io_block_spec_t *)spec;
143b114abb6SLionel Debieve cur = (mtd_dev_state_t *)dev_info->info;
144b114abb6SLionel Debieve entity->info = (uintptr_t)cur;
1459a9ea829SLionel Debieve cur->base = region->offset;
1469a9ea829SLionel Debieve cur->pos = 0U;
1479a9ea829SLionel Debieve cur->extra_offset = 0U;
1489a9ea829SLionel Debieve
1499a9ea829SLionel Debieve ret = mtd_add_extra_offset(cur, &extra_offset);
1509a9ea829SLionel Debieve if (ret != 0) {
1519a9ea829SLionel Debieve return ret;
1529a9ea829SLionel Debieve }
1539a9ea829SLionel Debieve
1549a9ea829SLionel Debieve cur->base += extra_offset;
155b114abb6SLionel Debieve
156b114abb6SLionel Debieve return 0;
157b114abb6SLionel Debieve }
158b114abb6SLionel Debieve
159b114abb6SLionel Debieve /* Seek to a specific position using offset */
mtd_seek(io_entity_t * entity,int mode,signed long long offset)160b114abb6SLionel Debieve static int mtd_seek(io_entity_t *entity, int mode, signed long long offset)
161b114abb6SLionel Debieve {
162b114abb6SLionel Debieve mtd_dev_state_t *cur;
1639a9ea829SLionel Debieve size_t extra_offset = 0U;
1649a9ea829SLionel Debieve int ret;
165b114abb6SLionel Debieve
166b114abb6SLionel Debieve assert((entity->info != (uintptr_t)NULL) && (offset >= 0));
167b114abb6SLionel Debieve
168b114abb6SLionel Debieve cur = (mtd_dev_state_t *)entity->info;
169b114abb6SLionel Debieve
170b114abb6SLionel Debieve switch (mode) {
171b114abb6SLionel Debieve case IO_SEEK_SET:
172b114abb6SLionel Debieve if ((offset >= 0) &&
173b114abb6SLionel Debieve ((unsigned long long)offset >= cur->size)) {
174b114abb6SLionel Debieve return -EINVAL;
175b114abb6SLionel Debieve }
176b114abb6SLionel Debieve
1779a9ea829SLionel Debieve cur->pos = offset;
178b114abb6SLionel Debieve break;
179b114abb6SLionel Debieve case IO_SEEK_CUR:
1809a9ea829SLionel Debieve if (((cur->base + cur->pos + (unsigned long long)offset) >=
181b114abb6SLionel Debieve cur->size) ||
1829a9ea829SLionel Debieve ((cur->base + cur->pos + (unsigned long long)offset) <
1839a9ea829SLionel Debieve cur->base + cur->pos)) {
184b114abb6SLionel Debieve return -EINVAL;
185b114abb6SLionel Debieve }
186b114abb6SLionel Debieve
1879a9ea829SLionel Debieve cur->pos += (unsigned long long)offset;
188b114abb6SLionel Debieve break;
189b114abb6SLionel Debieve default:
190b114abb6SLionel Debieve return -EINVAL;
191b114abb6SLionel Debieve }
192b114abb6SLionel Debieve
1939a9ea829SLionel Debieve ret = mtd_add_extra_offset(cur, &extra_offset);
1949a9ea829SLionel Debieve if (ret != 0) {
1959a9ea829SLionel Debieve return ret;
1969a9ea829SLionel Debieve }
1979a9ea829SLionel Debieve
1989a9ea829SLionel Debieve cur->extra_offset = extra_offset;
1999a9ea829SLionel Debieve
200b114abb6SLionel Debieve return 0;
201b114abb6SLionel Debieve }
202b114abb6SLionel Debieve
mtd_read(io_entity_t * entity,uintptr_t buffer,size_t length,size_t * out_length)203b114abb6SLionel Debieve static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
204b114abb6SLionel Debieve size_t *out_length)
205b114abb6SLionel Debieve {
206b114abb6SLionel Debieve mtd_dev_state_t *cur;
207b114abb6SLionel Debieve io_mtd_ops_t *ops;
208b114abb6SLionel Debieve int ret;
209b114abb6SLionel Debieve
210b114abb6SLionel Debieve assert(entity->info != (uintptr_t)NULL);
211b114abb6SLionel Debieve assert((length > 0U) && (buffer != (uintptr_t)NULL));
212b114abb6SLionel Debieve
213b114abb6SLionel Debieve cur = (mtd_dev_state_t *)entity->info;
214b114abb6SLionel Debieve ops = &cur->dev_spec->ops;
215b114abb6SLionel Debieve assert(ops->read != NULL);
216b114abb6SLionel Debieve
217*6e86b462SYann Gautier VERBOSE("Read at %llx into %lx, length %zu\n",
2189a9ea829SLionel Debieve cur->base + cur->pos, buffer, length);
2199a9ea829SLionel Debieve if ((cur->base + cur->pos + length) > cur->dev_spec->device_size) {
220b114abb6SLionel Debieve return -EINVAL;
221b114abb6SLionel Debieve }
222b114abb6SLionel Debieve
2239a9ea829SLionel Debieve ret = ops->read(cur->base + cur->pos + cur->extra_offset, buffer,
2249a9ea829SLionel Debieve length, out_length);
225b114abb6SLionel Debieve if (ret < 0) {
226b114abb6SLionel Debieve return ret;
227b114abb6SLionel Debieve }
228b114abb6SLionel Debieve
229b114abb6SLionel Debieve assert(*out_length == length);
2309a9ea829SLionel Debieve cur->pos += *out_length;
231b114abb6SLionel Debieve
232b114abb6SLionel Debieve return 0;
233b114abb6SLionel Debieve }
234b114abb6SLionel Debieve
mtd_close(io_entity_t * entity)235b114abb6SLionel Debieve static int mtd_close(io_entity_t *entity)
236b114abb6SLionel Debieve {
237b114abb6SLionel Debieve entity->info = (uintptr_t)NULL;
238b114abb6SLionel Debieve
239b114abb6SLionel Debieve return 0;
240b114abb6SLionel Debieve }
241b114abb6SLionel Debieve
mtd_dev_open(const uintptr_t dev_spec,io_dev_info_t ** dev_info)242b114abb6SLionel Debieve static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
243b114abb6SLionel Debieve {
244b114abb6SLionel Debieve mtd_dev_state_t *cur;
245b114abb6SLionel Debieve io_dev_info_t *info;
246b114abb6SLionel Debieve io_mtd_ops_t *ops;
247b114abb6SLionel Debieve int result;
248b114abb6SLionel Debieve
249b114abb6SLionel Debieve result = allocate_dev_info(&info);
250b114abb6SLionel Debieve if (result != 0) {
251b114abb6SLionel Debieve return -ENOENT;
252b114abb6SLionel Debieve }
253b114abb6SLionel Debieve
254b114abb6SLionel Debieve cur = (mtd_dev_state_t *)info->info;
255b114abb6SLionel Debieve cur->dev_spec = (io_mtd_dev_spec_t *)dev_spec;
256b114abb6SLionel Debieve *dev_info = info;
257b114abb6SLionel Debieve ops = &(cur->dev_spec->ops);
258b114abb6SLionel Debieve if (ops->init != NULL) {
259b114abb6SLionel Debieve result = ops->init(&cur->dev_spec->device_size,
260b114abb6SLionel Debieve &cur->dev_spec->erase_size);
261b114abb6SLionel Debieve }
262b114abb6SLionel Debieve
263b114abb6SLionel Debieve if (result == 0) {
264b114abb6SLionel Debieve cur->size = cur->dev_spec->device_size;
265b114abb6SLionel Debieve } else {
266b114abb6SLionel Debieve cur->size = 0ULL;
267b114abb6SLionel Debieve }
268b114abb6SLionel Debieve
269b114abb6SLionel Debieve return result;
270b114abb6SLionel Debieve }
271b114abb6SLionel Debieve
mtd_dev_close(io_dev_info_t * dev_info)272b114abb6SLionel Debieve static int mtd_dev_close(io_dev_info_t *dev_info)
273b114abb6SLionel Debieve {
274b114abb6SLionel Debieve return free_dev_info(dev_info);
275b114abb6SLionel Debieve }
276b114abb6SLionel Debieve
277b114abb6SLionel Debieve /* Exported functions */
278b114abb6SLionel Debieve
279b114abb6SLionel Debieve /* Register the MTD driver in the IO abstraction */
register_io_dev_mtd(const io_dev_connector_t ** dev_con)280b114abb6SLionel Debieve int register_io_dev_mtd(const io_dev_connector_t **dev_con)
281b114abb6SLionel Debieve {
282b114abb6SLionel Debieve int result;
283b114abb6SLionel Debieve
284b114abb6SLionel Debieve result = io_register_device(&dev_info_pool[0]);
285b114abb6SLionel Debieve if (result == 0) {
286b114abb6SLionel Debieve *dev_con = &mtd_dev_connector;
287b114abb6SLionel Debieve }
288b114abb6SLionel Debieve
289b114abb6SLionel Debieve return result;
290b114abb6SLionel Debieve }
291