2
* @brief Common interface for flash subsystem
5
* @author Andrey Gazukin
6
* @author Denis Deryugin
12
#include <drivers/block_dev.h>
13
#include <drivers/flash/flash.h>
17
struct flash_block_info *
18
flash_block_info_by_block(struct flash_dev *flashdev, int block) {
22
for (i = 0; i < flashdev->num_block_infos; i ++) {
23
if (cur <= block && block < (cur + flashdev->block_info[i].blocks) ) {
24
return &flashdev->block_info[i];
26
cur += flashdev->block_info[i].blocks;
33
flash_get_block_size(struct flash_dev *flashdev, int block) {
37
for (i = 0; i < flashdev->num_block_infos; i ++) {
38
if (cur <= block && block < (cur + flashdev->block_info[i].blocks) ) {
39
return flashdev->block_info[i].block_size;
41
cur += flashdev->block_info[i].blocks;
48
flash_get_block_by_offset(struct flash_dev *flashdev, unsigned long offset) {
51
unsigned long cur = 0;
53
for (i = 0; i < flashdev->num_block_infos; i++) {
54
for (j = 0; j < flashdev->block_info[i].blocks; j++) {
56
offset < (cur + flashdev->block_info[i].block_size) ) {
59
cur += flashdev->block_info[i].block_size;
68
flash_get_offset_by_block(struct flash_dev *flashdev, int block) {
71
unsigned long cur = 0;
73
for (i = 0; i < flashdev->num_block_infos; i++) {
74
for (j = 0; j < flashdev->block_info[i].blocks; j++) {
78
cur += flashdev->block_info[i].block_size;
87
flash_get_blocks_num(struct flash_dev *flashdev) {
91
for (i = 0; i < flashdev->num_block_infos; i ++) {
92
num += flashdev->block_info[i].blocks;
98
/* Handlers to check ranges and call device-specific functions */
99
int flash_read(struct flash_dev *flashdev, unsigned long offset, void *buf,
103
assert(flashdev->drv);
104
assert(flashdev->drv->flash_read);
106
assert(offset + len <= flashdev->size);
108
return flashdev->drv->flash_read(flashdev, offset, buf, len);
111
int flash_write(struct flash_dev *flashdev, unsigned long offset,
112
const void *buf, size_t len) {
115
assert(flashdev->drv);
116
assert(flashdev->drv->flash_program);
118
assert(offset + len <= flashdev->size);
120
return flashdev->drv->flash_program(flashdev, offset, buf, len);
123
int flash_erase(struct flash_dev *flashdev, uint32_t block) {
125
assert(flashdev->drv);
126
assert(flashdev->drv->flash_erase_block);
128
return flashdev->drv->flash_erase_block(flashdev, block);
131
struct flash_dev *flash_by_bdev(struct block_dev *bdev) {
132
return bdev->dev_module.dev_priv;
136
int flash_read_aligned(struct flash_dev *flashdev, unsigned long offset,
137
void *buff, size_t len) {
146
if (flashdev->fld_aligned_word) {
147
b = flashdev->fld_aligned_word;
148
word_size = flashdev->fld_word_size;
152
word_size = sizeof(word32);
155
head = offset % word_size;
158
size_t head_cnt = min(len, word_size - head);
161
flash_read(flashdev, offset, b, word_size);
162
memcpy(buff, b + head, head_cnt);
164
if (len <= head_cnt) {
173
for (i = 0; len >= word_size; i++) {
174
flash_read(flashdev, offset, b, word_size);
175
memcpy(buff, b, word_size);
183
flash_read(flashdev, offset, b, word_size);
184
memcpy(buff, b, len);
190
/* @brief Write non-aligned raw data to \b erased NAND flash
191
* @param offset Start position on disk
192
* @param buff Source of the data
193
* @param len Length of the data in bytes
195
* @returns Bytes written or negative error code
197
int flash_write_aligned(struct flash_dev *flashdev, unsigned long offset,
198
const void *buff, size_t len) {
207
if (flashdev->fld_aligned_word) {
208
b = flashdev->fld_aligned_word;
209
word_size = flashdev->fld_word_size;
213
word_size = sizeof(word32);
216
head = offset % word_size;
219
size_t head_write_cnt = min(len, word_size - head);
222
flash_read(flashdev, offset, b, word_size);
223
memcpy(b + head, buff, head_write_cnt);
224
flash_write(flashdev, offset, b, word_size);
226
if (len <= head_write_cnt) {
230
buff += head_write_cnt;
232
len -= head_write_cnt;
235
for (i = 0; len >= word_size; i++) {
236
memcpy(b, buff, word_size);
237
flash_write(flashdev, offset, b, word_size);
245
flash_read(flashdev, offset, b, word_size);
246
memcpy(b, buff, len);
247
flash_write(flashdev, offset, b, word_size);
253
int flash_copy_aligned(struct flash_dev *flashdev, unsigned long to,
254
unsigned long from, int len) {
260
tmp_len = min(len, sizeof(b));
262
if (0 > flash_read_aligned(flashdev, from, b, tmp_len)) {
265
if (0 > flash_write_aligned(flashdev, to, b, tmp_len)) {
277
int flash_copy_block(struct flash_dev *flashdev, unsigned int to,
278
unsigned long from) {
282
unsigned long off_to;
283
unsigned long off_from;
285
block_size = flash_get_block_size(flashdev, to);
286
assert(block_size == flash_get_block_size(flashdev, from));
288
off_to = flash_get_offset_by_block(flashdev, to);
289
off_from = flash_get_offset_by_block(flashdev, from);
291
flash_erase(flashdev, to);
293
for (off = 0; off < block_size; off += sizeof(buf)) {
294
flash_read(flashdev, off_from + off, buf, sizeof(buf));
295
flash_write(flashdev, off_to + off, buf, sizeof(buf));