io_mtd.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <common/debug.h>
  10. #include <drivers/io/io_driver.h>
  11. #include <drivers/io/io_mtd.h>
  12. #include <lib/utils.h>
  13. #include <platform_def.h>
  14. typedef struct {
  15. io_mtd_dev_spec_t *dev_spec;
  16. uintptr_t base;
  17. unsigned long long pos; /* Offset in bytes */
  18. unsigned long long size; /* Size of device in bytes */
  19. unsigned long long extra_offset; /* Extra offset in bytes */
  20. } mtd_dev_state_t;
  21. io_type_t device_type_mtd(void);
  22. static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
  23. io_entity_t *entity);
  24. static int mtd_seek(io_entity_t *entity, int mode, signed long long offset);
  25. static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
  26. size_t *length_read);
  27. static int mtd_close(io_entity_t *entity);
  28. static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info);
  29. static int mtd_dev_close(io_dev_info_t *dev_info);
  30. static const io_dev_connector_t mtd_dev_connector = {
  31. .dev_open = mtd_dev_open
  32. };
  33. static const io_dev_funcs_t mtd_dev_funcs = {
  34. .type = device_type_mtd,
  35. .open = mtd_open,
  36. .seek = mtd_seek,
  37. .read = mtd_read,
  38. .close = mtd_close,
  39. .dev_close = mtd_dev_close,
  40. };
  41. static mtd_dev_state_t state_pool[MAX_IO_MTD_DEVICES];
  42. static io_dev_info_t dev_info_pool[MAX_IO_MTD_DEVICES];
  43. io_type_t device_type_mtd(void)
  44. {
  45. return IO_TYPE_MTD;
  46. }
  47. /* Locate a MTD state in the pool, specified by address */
  48. static int find_first_mtd_state(const io_mtd_dev_spec_t *dev_spec,
  49. unsigned int *index_out)
  50. {
  51. unsigned int index;
  52. int result = -ENOENT;
  53. for (index = 0U; index < MAX_IO_MTD_DEVICES; index++) {
  54. /* dev_spec is used as identifier since it's unique */
  55. if (state_pool[index].dev_spec == dev_spec) {
  56. result = 0;
  57. *index_out = index;
  58. break;
  59. }
  60. }
  61. return result;
  62. }
  63. /* Allocate a device info from the pool */
  64. static int allocate_dev_info(io_dev_info_t **dev_info)
  65. {
  66. unsigned int index = 0U;
  67. int result;
  68. result = find_first_mtd_state(NULL, &index);
  69. if (result != 0) {
  70. return -ENOMEM;
  71. }
  72. dev_info_pool[index].funcs = &mtd_dev_funcs;
  73. dev_info_pool[index].info = (uintptr_t)&state_pool[index];
  74. *dev_info = &dev_info_pool[index];
  75. return 0;
  76. }
  77. /* Release a device info from the pool */
  78. static int free_dev_info(io_dev_info_t *dev_info)
  79. {
  80. int result;
  81. unsigned int index = 0U;
  82. mtd_dev_state_t *state;
  83. state = (mtd_dev_state_t *)dev_info->info;
  84. result = find_first_mtd_state(state->dev_spec, &index);
  85. if (result != 0) {
  86. return result;
  87. }
  88. zeromem(state, sizeof(mtd_dev_state_t));
  89. zeromem(dev_info, sizeof(io_dev_info_t));
  90. return 0;
  91. }
  92. static int mtd_add_extra_offset(mtd_dev_state_t *cur, size_t *extra_offset)
  93. {
  94. io_mtd_ops_t *ops = &cur->dev_spec->ops;
  95. int ret;
  96. if (ops->seek == NULL) {
  97. return 0;
  98. }
  99. ret = ops->seek(cur->base, cur->pos, extra_offset);
  100. if (ret != 0) {
  101. ERROR("%s: Seek error %d\n", __func__, ret);
  102. return ret;
  103. }
  104. return 0;
  105. }
  106. static int mtd_open(io_dev_info_t *dev_info, const uintptr_t spec,
  107. io_entity_t *entity)
  108. {
  109. mtd_dev_state_t *cur;
  110. io_block_spec_t *region;
  111. size_t extra_offset = 0U;
  112. int ret;
  113. assert((dev_info->info != 0UL) && (entity->info == 0UL));
  114. region = (io_block_spec_t *)spec;
  115. cur = (mtd_dev_state_t *)dev_info->info;
  116. entity->info = (uintptr_t)cur;
  117. cur->base = region->offset;
  118. cur->pos = 0U;
  119. cur->extra_offset = 0U;
  120. ret = mtd_add_extra_offset(cur, &extra_offset);
  121. if (ret != 0) {
  122. return ret;
  123. }
  124. cur->base += extra_offset;
  125. return 0;
  126. }
  127. /* Seek to a specific position using offset */
  128. static int mtd_seek(io_entity_t *entity, int mode, signed long long offset)
  129. {
  130. mtd_dev_state_t *cur;
  131. size_t extra_offset = 0U;
  132. int ret;
  133. assert((entity->info != (uintptr_t)NULL) && (offset >= 0));
  134. cur = (mtd_dev_state_t *)entity->info;
  135. switch (mode) {
  136. case IO_SEEK_SET:
  137. if ((offset >= 0) &&
  138. ((unsigned long long)offset >= cur->size)) {
  139. return -EINVAL;
  140. }
  141. cur->pos = offset;
  142. break;
  143. case IO_SEEK_CUR:
  144. if (((cur->base + cur->pos + (unsigned long long)offset) >=
  145. cur->size) ||
  146. ((cur->base + cur->pos + (unsigned long long)offset) <
  147. cur->base + cur->pos)) {
  148. return -EINVAL;
  149. }
  150. cur->pos += (unsigned long long)offset;
  151. break;
  152. default:
  153. return -EINVAL;
  154. }
  155. ret = mtd_add_extra_offset(cur, &extra_offset);
  156. if (ret != 0) {
  157. return ret;
  158. }
  159. cur->extra_offset = extra_offset;
  160. return 0;
  161. }
  162. static int mtd_read(io_entity_t *entity, uintptr_t buffer, size_t length,
  163. size_t *out_length)
  164. {
  165. mtd_dev_state_t *cur;
  166. io_mtd_ops_t *ops;
  167. int ret;
  168. assert(entity->info != (uintptr_t)NULL);
  169. assert((length > 0U) && (buffer != (uintptr_t)NULL));
  170. cur = (mtd_dev_state_t *)entity->info;
  171. ops = &cur->dev_spec->ops;
  172. assert(ops->read != NULL);
  173. VERBOSE("Read at %llx into %lx, length %zu\n",
  174. cur->base + cur->pos, buffer, length);
  175. if ((cur->base + cur->pos + length) > cur->dev_spec->device_size) {
  176. return -EINVAL;
  177. }
  178. ret = ops->read(cur->base + cur->pos + cur->extra_offset, buffer,
  179. length, out_length);
  180. if (ret < 0) {
  181. return ret;
  182. }
  183. assert(*out_length == length);
  184. cur->pos += *out_length;
  185. return 0;
  186. }
  187. static int mtd_close(io_entity_t *entity)
  188. {
  189. entity->info = (uintptr_t)NULL;
  190. return 0;
  191. }
  192. static int mtd_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info)
  193. {
  194. mtd_dev_state_t *cur;
  195. io_dev_info_t *info;
  196. io_mtd_ops_t *ops;
  197. int result;
  198. result = allocate_dev_info(&info);
  199. if (result != 0) {
  200. return -ENOENT;
  201. }
  202. cur = (mtd_dev_state_t *)info->info;
  203. cur->dev_spec = (io_mtd_dev_spec_t *)dev_spec;
  204. *dev_info = info;
  205. ops = &(cur->dev_spec->ops);
  206. if (ops->init != NULL) {
  207. result = ops->init(&cur->dev_spec->device_size,
  208. &cur->dev_spec->erase_size);
  209. }
  210. if (result == 0) {
  211. cur->size = cur->dev_spec->device_size;
  212. } else {
  213. cur->size = 0ULL;
  214. }
  215. return result;
  216. }
  217. static int mtd_dev_close(io_dev_info_t *dev_info)
  218. {
  219. return free_dev_info(dev_info);
  220. }
  221. /* Exported functions */
  222. /* Register the MTD driver in the IO abstraction */
  223. int register_io_dev_mtd(const io_dev_connector_t **dev_con)
  224. {
  225. int result;
  226. result = io_register_device(&dev_info_pool[0]);
  227. if (result == 0) {
  228. *dev_con = &mtd_dev_connector;
  229. }
  230. return result;
  231. }