-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathNuSDFlashSimBlockDevice.cpp
More file actions
205 lines (167 loc) · 6.26 KB
/
NuSDFlashSimBlockDevice.cpp
File metadata and controls
205 lines (167 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
* Copyright (c) 2021, Nuvoton Technology Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Nuvoton mbed enabled targets which support SD card of SD bus mode */
#if TARGET_NUVOTON
#include "NuSDFlashSimBlockDevice.h"
#include "mbed_toolchain.h"
/* Emulate flash program attribute: 0 doesn't program to 1 */
#define NU_SDH_FLASH_PROG_ATR MBED_CONF_NUSD_FLASHSIM_PROGRAM_ATTRIBUTE
/* Emulate flash erase unit of specified size */
#define NU_SDH_FLASH_SECTOR_SIZE MBED_CONF_NUSD_FLASHSIM_ERASE_UNIT_SIZE
/* SD card sector size */
#define SDH_SECTOR_SIZE 512
/* SDH DMA compatible buffer
*
* SDH DMA buffer location requires to be:
* (1) Word-aligned
* (2) Located in 0x2xxxxxxx/0x3xxxxxxx region. Check linker files to ensure global/static
* variables are placed in this region.
*
* SDH DMA buffer size DMA_BUF_SIZE must be a multiple of 512-byte block size.
* Its value is estimated to trade memory footprint off against performance.
*
*/
#define DMA_BUFF_SIZE SDH_SECTOR_SIZE
MBED_ALIGN(4) static uint8_t dma_buff[DMA_BUFF_SIZE];
/* SDH Flash sector size must be a multiple of SDH sector size. */
static_assert((NU_SDH_FLASH_SECTOR_SIZE % SDH_SECTOR_SIZE) == 0,
"NU_SDH_FLASH_SECTOR_SIZE must a multiple of SDH_SECTOR_SIZE");
/* DMA buffer size must be a multiple of SDH sector size. */
static_assert((DMA_BUFF_SIZE % SDH_SECTOR_SIZE) == 0,
"DMA_BUFF_SIZE must a multiple of SDH_SECTOR_SIZE");
NuSDFlashSimBlockDevice::NuSDFlashSimBlockDevice() :
NuSDBlockDevice()
{
}
NuSDFlashSimBlockDevice::NuSDFlashSimBlockDevice(PinName sd_dat0, PinName sd_dat1, PinName sd_dat2, PinName sd_dat3,
PinName sd_cmd, PinName sd_clk, PinName sd_cdn) :
NuSDBlockDevice(sd_dat0, sd_dat1, sd_dat2, sd_dat3, sd_cmd, sd_clk, sd_cdn)
{
}
NuSDFlashSimBlockDevice::~NuSDFlashSimBlockDevice()
{
}
int NuSDFlashSimBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
{
_lock.lock();
int err = BD_ERROR_OK;
/* For easy implementation, we always use SDH DMA-compatible buffer for intermediate. */
const uint8_t *b_pos = (const uint8_t *) b;
bd_addr_t addr_pos = addr;
bd_size_t rmn = size;
while (rmn) {
uint32_t sector_offset = addr_pos % SDH_SECTOR_SIZE;
uint32_t todo_size = DMA_BUFF_SIZE - sector_offset;
todo_size = (todo_size >= rmn) ? rmn : todo_size;
/* [begin_sector, end_sector) */
uint32_t begin_sector = addr_pos / SDH_SECTOR_SIZE;
uint32_t end_sector = (addr_pos + todo_size - 1 + SDH_SECTOR_SIZE) / SDH_SECTOR_SIZE;
err = NuSDBlockDevice::read(dma_buff, begin_sector * SDH_SECTOR_SIZE, (end_sector - begin_sector) * SDH_SECTOR_SIZE);
if (err != BD_ERROR_OK) {
return err;
}
#if NU_SDH_FLASH_PROG_ATR
{
const uint8_t *b_pos2 = b_pos;
const uint8_t *b_end2 = b_pos + todo_size;
uint8_t *dma_buff_pos = dma_buff + sector_offset;
while (b_pos2 < b_end2) {
*dma_buff_pos &= *b_pos2;
dma_buff_pos ++;
b_pos2 ++;
}
}
#else
memcpy(dma_buff + sector_offset, b_pos, todo_size);
#endif
err = NuSDBlockDevice::program(dma_buff, begin_sector * SDH_SECTOR_SIZE, (end_sector - begin_sector) * SDH_SECTOR_SIZE);
if (err != BD_ERROR_OK) {
return err;
}
b_pos += todo_size;
addr_pos += todo_size;
rmn -= todo_size;
}
_lock.unlock();
return err;
}
int NuSDFlashSimBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
{
_lock.lock();
int err = BD_ERROR_OK;
/* For easy b, we always use SDH DMA-compatible buffer for intermediate. */
uint8_t *b_pos = (uint8_t *) b;
bd_addr_t addr_pos = addr;
bd_size_t rmn = size;
while (rmn) {
uint32_t sector_offset = addr_pos % SDH_SECTOR_SIZE;
uint32_t todo_size = DMA_BUFF_SIZE - sector_offset;
todo_size = (todo_size >= rmn) ? rmn : todo_size;
/* [begin_sector, end_sector) */
uint32_t begin_sector = addr_pos / SDH_SECTOR_SIZE;
uint32_t end_sector = (addr_pos + todo_size - 1 + SDH_SECTOR_SIZE) / SDH_SECTOR_SIZE;
err = NuSDBlockDevice::read(dma_buff, begin_sector * SDH_SECTOR_SIZE, (end_sector - begin_sector) * SDH_SECTOR_SIZE);
if (err != BD_ERROR_OK) {
return err;
}
memcpy(b_pos, dma_buff + sector_offset, todo_size);
b_pos += todo_size;
addr_pos += todo_size;
rmn -= todo_size;
}
_lock.unlock();
return err;
}
int NuSDFlashSimBlockDevice::erase(bd_addr_t addr, bd_size_t size)
{
_lock.lock();
int err = BD_ERROR_OK;
memset(dma_buff, 0xFF, SDH_SECTOR_SIZE);
/* Simulate flash sector erase */
bd_addr_t addr_pos = addr / NU_SDH_FLASH_SECTOR_SIZE * NU_SDH_FLASH_SECTOR_SIZE;
bd_addr_t addr_end = (addr_pos + size + NU_SDH_FLASH_SECTOR_SIZE - 1) / NU_SDH_FLASH_SECTOR_SIZE * NU_SDH_FLASH_SECTOR_SIZE;
for (; addr_pos < addr_end; addr_pos += SDH_SECTOR_SIZE) {
err = NuSDBlockDevice::program(dma_buff, addr_pos, SDH_SECTOR_SIZE);
if (err != BD_ERROR_OK) {
return err;
}
}
_lock.unlock();
return err;
}
bd_size_t NuSDFlashSimBlockDevice::get_read_size() const
{
return 1;
}
bd_size_t NuSDFlashSimBlockDevice::get_program_size() const
{
return 1;
}
bd_size_t NuSDFlashSimBlockDevice::get_erase_size() const
{
return NU_SDH_FLASH_SECTOR_SIZE;
}
bd_size_t NuSDFlashSimBlockDevice::get_erase_size(bd_addr_t addr) const
{
return NU_SDH_FLASH_SECTOR_SIZE;
}
const char *NuSDFlashSimBlockDevice::NuSDFlashSimBlockDevice::get_type() const
{
return "NUSD_FLASHSIM";
}
#endif /* TARGET_NUVOTON */