xref: /rk3399_ARM-atf/drivers/io/io_mtd.c (revision 9a9ea82948fd2f1459b6351cb0641f3f77b4e6de)
1b114abb6SLionel Debieve /*
2*9a9ea829SLionel Debieve  * Copyright (c) 2019-2021, 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 <platform_def.h>
12b114abb6SLionel Debieve 
13b114abb6SLionel Debieve #include <common/debug.h>
14b114abb6SLionel Debieve #include <drivers/io/io_driver.h>
15b114abb6SLionel Debieve #include <drivers/io/io_mtd.h>
16b114abb6SLionel Debieve #include <lib/utils.h>
17b114abb6SLionel Debieve 
18b114abb6SLionel Debieve typedef struct {
19b114abb6SLionel Debieve 	io_mtd_dev_spec_t	*dev_spec;
20b114abb6SLionel Debieve 	uintptr_t		base;
21*9a9ea829SLionel Debieve 	unsigned long long	pos;		/* Offset in bytes */
22b114abb6SLionel Debieve 	unsigned long long	size;		/* Size of device in bytes */
23*9a9ea829SLionel 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 
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 */
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 */
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 */
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 
114*9a9ea829SLionel Debieve static int mtd_add_extra_offset(mtd_dev_state_t *cur, size_t *extra_offset)
115*9a9ea829SLionel Debieve {
116*9a9ea829SLionel Debieve 	io_mtd_ops_t *ops = &cur->dev_spec->ops;
117*9a9ea829SLionel Debieve 	int ret;
118*9a9ea829SLionel Debieve 
119*9a9ea829SLionel Debieve 	if (ops->seek == NULL) {
120*9a9ea829SLionel Debieve 		return 0;
121*9a9ea829SLionel Debieve 	}
122*9a9ea829SLionel Debieve 
123*9a9ea829SLionel Debieve 	ret = ops->seek(cur->base, cur->pos, extra_offset);
124*9a9ea829SLionel Debieve 	if (ret != 0) {
125*9a9ea829SLionel Debieve 		ERROR("%s: Seek error %d\n", __func__, ret);
126*9a9ea829SLionel Debieve 		return ret;
127*9a9ea829SLionel Debieve 	}
128*9a9ea829SLionel Debieve 
129*9a9ea829SLionel Debieve 	return 0;
130*9a9ea829SLionel Debieve }
131*9a9ea829SLionel Debieve 
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;
136*9a9ea829SLionel Debieve 	io_block_spec_t *region;
137*9a9ea829SLionel Debieve 	size_t extra_offset = 0U;
138*9a9ea829SLionel Debieve 	int ret;
139b114abb6SLionel Debieve 
140b114abb6SLionel Debieve 	assert((dev_info->info != 0UL) && (entity->info == 0UL));
141b114abb6SLionel Debieve 
142*9a9ea829SLionel Debieve 	region = (io_block_spec_t *)spec;
143b114abb6SLionel Debieve 	cur = (mtd_dev_state_t *)dev_info->info;
144b114abb6SLionel Debieve 	entity->info = (uintptr_t)cur;
145*9a9ea829SLionel Debieve 	cur->base = region->offset;
146*9a9ea829SLionel Debieve 	cur->pos = 0U;
147*9a9ea829SLionel Debieve 	cur->extra_offset = 0U;
148*9a9ea829SLionel Debieve 
149*9a9ea829SLionel Debieve 	ret = mtd_add_extra_offset(cur, &extra_offset);
150*9a9ea829SLionel Debieve 	if (ret != 0) {
151*9a9ea829SLionel Debieve 		return ret;
152*9a9ea829SLionel Debieve 	}
153*9a9ea829SLionel Debieve 
154*9a9ea829SLionel Debieve 	cur->base += extra_offset;
155b114abb6SLionel Debieve 
156b114abb6SLionel Debieve 	return 0;
157b114abb6SLionel Debieve }
158b114abb6SLionel Debieve 
159b114abb6SLionel Debieve /* Seek to a specific position using 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;
163*9a9ea829SLionel Debieve 	size_t extra_offset = 0U;
164*9a9ea829SLionel 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 
177*9a9ea829SLionel Debieve 		cur->pos = offset;
178b114abb6SLionel Debieve 		break;
179b114abb6SLionel Debieve 	case IO_SEEK_CUR:
180*9a9ea829SLionel Debieve 		if (((cur->base + cur->pos + (unsigned long long)offset) >=
181b114abb6SLionel Debieve 		     cur->size) ||
182*9a9ea829SLionel Debieve 		    ((cur->base + cur->pos + (unsigned long long)offset) <
183*9a9ea829SLionel Debieve 		     cur->base + cur->pos)) {
184b114abb6SLionel Debieve 			return -EINVAL;
185b114abb6SLionel Debieve 		}
186b114abb6SLionel Debieve 
187*9a9ea829SLionel Debieve 		cur->pos += (unsigned long long)offset;
188b114abb6SLionel Debieve 		break;
189b114abb6SLionel Debieve 	default:
190b114abb6SLionel Debieve 		return -EINVAL;
191b114abb6SLionel Debieve 	}
192b114abb6SLionel Debieve 
193*9a9ea829SLionel Debieve 	ret = mtd_add_extra_offset(cur, &extra_offset);
194*9a9ea829SLionel Debieve 	if (ret != 0) {
195*9a9ea829SLionel Debieve 		return ret;
196*9a9ea829SLionel Debieve 	}
197*9a9ea829SLionel Debieve 
198*9a9ea829SLionel Debieve 	cur->extra_offset = extra_offset;
199*9a9ea829SLionel Debieve 
200b114abb6SLionel Debieve 	return 0;
201b114abb6SLionel Debieve }
202b114abb6SLionel Debieve 
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 
217b114abb6SLionel Debieve 	VERBOSE("Read at %llx into %lx, length %zi\n",
218*9a9ea829SLionel Debieve 		cur->base + cur->pos, buffer, length);
219*9a9ea829SLionel Debieve 	if ((cur->base + cur->pos + length) > cur->dev_spec->device_size) {
220b114abb6SLionel Debieve 		return -EINVAL;
221b114abb6SLionel Debieve 	}
222b114abb6SLionel Debieve 
223*9a9ea829SLionel Debieve 	ret = ops->read(cur->base + cur->pos + cur->extra_offset, buffer,
224*9a9ea829SLionel Debieve 			length, out_length);
225b114abb6SLionel Debieve 	if (ret < 0) {
226b114abb6SLionel Debieve 		return ret;
227b114abb6SLionel Debieve 	}
228b114abb6SLionel Debieve 
229b114abb6SLionel Debieve 	assert(*out_length == length);
230*9a9ea829SLionel Debieve 	cur->pos += *out_length;
231b114abb6SLionel Debieve 
232b114abb6SLionel Debieve 	return 0;
233b114abb6SLionel Debieve }
234b114abb6SLionel Debieve 
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 
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 
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 */
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