mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 17 23:23:45 2019 +0000
Revision:
0:5b88d5760320
Child:
1:9db0e321a9f4
mbed-os5 only for TYBLE16

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:5b88d5760320 1 /* mbed Microcontroller Library
kenjiArai 0:5b88d5760320 2 * Copyright (c) 2018 ARM Limited
kenjiArai 0:5b88d5760320 3 *
kenjiArai 0:5b88d5760320 4 * Licensed under the Apache License, Version 2.0 (the "License");
kenjiArai 0:5b88d5760320 5 * you may not use this file except in compliance with the License.
kenjiArai 0:5b88d5760320 6 * You may obtain a copy of the License at
kenjiArai 0:5b88d5760320 7 *
kenjiArai 0:5b88d5760320 8 * http://www.apache.org/licenses/LICENSE-2.0
kenjiArai 0:5b88d5760320 9 *
kenjiArai 0:5b88d5760320 10 * Unless required by applicable law or agreed to in writing, software
kenjiArai 0:5b88d5760320 11 * distributed under the License is distributed on an "AS IS" BASIS,
kenjiArai 0:5b88d5760320 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kenjiArai 0:5b88d5760320 13 * See the License for the specific language governing permissions and
kenjiArai 0:5b88d5760320 14 * limitations under the License.
kenjiArai 0:5b88d5760320 15 */
kenjiArai 0:5b88d5760320 16
kenjiArai 0:5b88d5760320 17 #include "BufferedBlockDevice.h"
kenjiArai 0:5b88d5760320 18 #include "platform/mbed_assert.h"
kenjiArai 0:5b88d5760320 19 #include "platform/mbed_atomic.h"
kenjiArai 0:5b88d5760320 20 #include <algorithm>
kenjiArai 0:5b88d5760320 21 #include <string.h>
kenjiArai 0:5b88d5760320 22
kenjiArai 0:5b88d5760320 23 namespace mbed {
kenjiArai 0:5b88d5760320 24
kenjiArai 0:5b88d5760320 25 static inline uint32_t align_down(bd_size_t val, bd_size_t size)
kenjiArai 0:5b88d5760320 26 {
kenjiArai 0:5b88d5760320 27 return val / size * size;
kenjiArai 0:5b88d5760320 28 }
kenjiArai 0:5b88d5760320 29
kenjiArai 0:5b88d5760320 30 BufferedBlockDevice::BufferedBlockDevice(BlockDevice *bd)
kenjiArai 0:5b88d5760320 31 : _bd(bd), _bd_program_size(0), _bd_read_size(0), _write_cache_addr(0), _write_cache_valid(false),
kenjiArai 0:5b88d5760320 32 _write_cache(0), _read_buf(0), _init_ref_count(0), _is_initialized(false)
kenjiArai 0:5b88d5760320 33 {
kenjiArai 0:5b88d5760320 34 }
kenjiArai 0:5b88d5760320 35
kenjiArai 0:5b88d5760320 36 BufferedBlockDevice::~BufferedBlockDevice()
kenjiArai 0:5b88d5760320 37 {
kenjiArai 0:5b88d5760320 38 deinit();
kenjiArai 0:5b88d5760320 39 }
kenjiArai 0:5b88d5760320 40
kenjiArai 0:5b88d5760320 41 int BufferedBlockDevice::init()
kenjiArai 0:5b88d5760320 42 {
kenjiArai 0:5b88d5760320 43 uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);
kenjiArai 0:5b88d5760320 44
kenjiArai 0:5b88d5760320 45 if (val != 1) {
kenjiArai 0:5b88d5760320 46 return BD_ERROR_OK;
kenjiArai 0:5b88d5760320 47 }
kenjiArai 0:5b88d5760320 48
kenjiArai 0:5b88d5760320 49 int err = _bd->init();
kenjiArai 0:5b88d5760320 50 if (err) {
kenjiArai 0:5b88d5760320 51 return err;
kenjiArai 0:5b88d5760320 52 }
kenjiArai 0:5b88d5760320 53
kenjiArai 0:5b88d5760320 54 _bd_read_size = _bd->get_read_size();
kenjiArai 0:5b88d5760320 55 _bd_program_size = _bd->get_program_size();
kenjiArai 0:5b88d5760320 56 _bd_size = _bd->size();
kenjiArai 0:5b88d5760320 57
kenjiArai 0:5b88d5760320 58 if (!_write_cache) {
kenjiArai 0:5b88d5760320 59 _write_cache = new uint8_t[_bd_program_size];
kenjiArai 0:5b88d5760320 60 }
kenjiArai 0:5b88d5760320 61
kenjiArai 0:5b88d5760320 62 if (!_read_buf) {
kenjiArai 0:5b88d5760320 63 _read_buf = new uint8_t[_bd_read_size];
kenjiArai 0:5b88d5760320 64 }
kenjiArai 0:5b88d5760320 65
kenjiArai 0:5b88d5760320 66 invalidate_write_cache();
kenjiArai 0:5b88d5760320 67
kenjiArai 0:5b88d5760320 68 _is_initialized = true;
kenjiArai 0:5b88d5760320 69 return BD_ERROR_OK;
kenjiArai 0:5b88d5760320 70 }
kenjiArai 0:5b88d5760320 71
kenjiArai 0:5b88d5760320 72 int BufferedBlockDevice::deinit()
kenjiArai 0:5b88d5760320 73 {
kenjiArai 0:5b88d5760320 74 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 75 return BD_ERROR_OK;
kenjiArai 0:5b88d5760320 76 }
kenjiArai 0:5b88d5760320 77
kenjiArai 0:5b88d5760320 78 uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1);
kenjiArai 0:5b88d5760320 79
kenjiArai 0:5b88d5760320 80 if (val) {
kenjiArai 0:5b88d5760320 81 return BD_ERROR_OK;
kenjiArai 0:5b88d5760320 82 }
kenjiArai 0:5b88d5760320 83
kenjiArai 0:5b88d5760320 84 delete[] _write_cache;
kenjiArai 0:5b88d5760320 85 _write_cache = 0;
kenjiArai 0:5b88d5760320 86 delete[] _read_buf;
kenjiArai 0:5b88d5760320 87 _read_buf = 0;
kenjiArai 0:5b88d5760320 88 _is_initialized = false;
kenjiArai 0:5b88d5760320 89 return _bd->deinit();
kenjiArai 0:5b88d5760320 90 }
kenjiArai 0:5b88d5760320 91
kenjiArai 0:5b88d5760320 92 int BufferedBlockDevice::flush()
kenjiArai 0:5b88d5760320 93 {
kenjiArai 0:5b88d5760320 94 MBED_ASSERT(_write_cache);
kenjiArai 0:5b88d5760320 95 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 96 return BD_ERROR_DEVICE_ERROR;
kenjiArai 0:5b88d5760320 97 }
kenjiArai 0:5b88d5760320 98
kenjiArai 0:5b88d5760320 99 if (_write_cache_valid) {
kenjiArai 0:5b88d5760320 100 int ret = _bd->program(_write_cache, _write_cache_addr, _bd_program_size);
kenjiArai 0:5b88d5760320 101 if (ret) {
kenjiArai 0:5b88d5760320 102 return ret;
kenjiArai 0:5b88d5760320 103 }
kenjiArai 0:5b88d5760320 104 invalidate_write_cache();
kenjiArai 0:5b88d5760320 105 }
kenjiArai 0:5b88d5760320 106 return 0;
kenjiArai 0:5b88d5760320 107 }
kenjiArai 0:5b88d5760320 108
kenjiArai 0:5b88d5760320 109 void BufferedBlockDevice::invalidate_write_cache()
kenjiArai 0:5b88d5760320 110 {
kenjiArai 0:5b88d5760320 111 _write_cache_addr = _bd_size;
kenjiArai 0:5b88d5760320 112 _write_cache_valid = false;
kenjiArai 0:5b88d5760320 113 }
kenjiArai 0:5b88d5760320 114
kenjiArai 0:5b88d5760320 115 int BufferedBlockDevice::sync()
kenjiArai 0:5b88d5760320 116 {
kenjiArai 0:5b88d5760320 117 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 118 return BD_ERROR_DEVICE_ERROR;
kenjiArai 0:5b88d5760320 119 }
kenjiArai 0:5b88d5760320 120
kenjiArai 0:5b88d5760320 121 MBED_ASSERT(_write_cache);
kenjiArai 0:5b88d5760320 122 int ret = flush();
kenjiArai 0:5b88d5760320 123 if (ret) {
kenjiArai 0:5b88d5760320 124 return ret;
kenjiArai 0:5b88d5760320 125 }
kenjiArai 0:5b88d5760320 126 return _bd->sync();
kenjiArai 0:5b88d5760320 127 }
kenjiArai 0:5b88d5760320 128
kenjiArai 0:5b88d5760320 129 int BufferedBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
kenjiArai 0:5b88d5760320 130 {
kenjiArai 0:5b88d5760320 131 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 132 return BD_ERROR_DEVICE_ERROR;
kenjiArai 0:5b88d5760320 133 }
kenjiArai 0:5b88d5760320 134
kenjiArai 0:5b88d5760320 135 MBED_ASSERT(_write_cache && _read_buf);
kenjiArai 0:5b88d5760320 136 // Common case - no need to involve write cache or read buffer
kenjiArai 0:5b88d5760320 137 if (_bd->is_valid_read(addr, size) &&
kenjiArai 0:5b88d5760320 138 ((addr + size <= _write_cache_addr) || (addr > _write_cache_addr + _bd_program_size))) {
kenjiArai 0:5b88d5760320 139 return _bd->read(b, addr, size);
kenjiArai 0:5b88d5760320 140 }
kenjiArai 0:5b88d5760320 141
kenjiArai 0:5b88d5760320 142 uint8_t *buf = static_cast<uint8_t *>(b);
kenjiArai 0:5b88d5760320 143
kenjiArai 0:5b88d5760320 144 // Read logic: Split read to chunks, according to whether we cross the write cache
kenjiArai 0:5b88d5760320 145 while (size) {
kenjiArai 0:5b88d5760320 146 bd_size_t chunk;
kenjiArai 0:5b88d5760320 147 bool read_from_bd = true;
kenjiArai 0:5b88d5760320 148 if (addr < _write_cache_addr) {
kenjiArai 0:5b88d5760320 149 chunk = std::min(size, _write_cache_addr - addr);
kenjiArai 0:5b88d5760320 150 } else if ((addr >= _write_cache_addr) && (addr < _write_cache_addr + _bd_program_size)) {
kenjiArai 0:5b88d5760320 151 // One case we need to take our data from cache
kenjiArai 0:5b88d5760320 152 chunk = std::min(size, _bd_program_size - addr % _bd_program_size);
kenjiArai 0:5b88d5760320 153 memcpy(buf, _write_cache + addr % _bd_program_size, chunk);
kenjiArai 0:5b88d5760320 154 read_from_bd = false;
kenjiArai 0:5b88d5760320 155 } else {
kenjiArai 0:5b88d5760320 156 chunk = size;
kenjiArai 0:5b88d5760320 157 }
kenjiArai 0:5b88d5760320 158
kenjiArai 0:5b88d5760320 159 // Now, in case we read from the BD, make sure we are aligned with its read size.
kenjiArai 0:5b88d5760320 160 // If not, use read buffer as a helper.
kenjiArai 0:5b88d5760320 161 if (read_from_bd) {
kenjiArai 0:5b88d5760320 162 bd_size_t offs_in_read_buf = addr % _bd_read_size;
kenjiArai 0:5b88d5760320 163 int ret;
kenjiArai 0:5b88d5760320 164 if (offs_in_read_buf || (chunk < _bd_read_size)) {
kenjiArai 0:5b88d5760320 165 chunk = std::min(chunk, _bd_read_size - offs_in_read_buf);
kenjiArai 0:5b88d5760320 166 ret = _bd->read(_read_buf, addr - offs_in_read_buf, _bd_read_size);
kenjiArai 0:5b88d5760320 167 memcpy(buf, _read_buf + offs_in_read_buf, chunk);
kenjiArai 0:5b88d5760320 168 } else {
kenjiArai 0:5b88d5760320 169 chunk = align_down(chunk, _bd_read_size);
kenjiArai 0:5b88d5760320 170 ret = _bd->read(buf, addr, chunk);
kenjiArai 0:5b88d5760320 171 }
kenjiArai 0:5b88d5760320 172 if (ret) {
kenjiArai 0:5b88d5760320 173 return ret;
kenjiArai 0:5b88d5760320 174 }
kenjiArai 0:5b88d5760320 175 }
kenjiArai 0:5b88d5760320 176
kenjiArai 0:5b88d5760320 177 buf += chunk;
kenjiArai 0:5b88d5760320 178 addr += chunk;
kenjiArai 0:5b88d5760320 179 size -= chunk;
kenjiArai 0:5b88d5760320 180 }
kenjiArai 0:5b88d5760320 181
kenjiArai 0:5b88d5760320 182 return 0;
kenjiArai 0:5b88d5760320 183 }
kenjiArai 0:5b88d5760320 184
kenjiArai 0:5b88d5760320 185 int BufferedBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
kenjiArai 0:5b88d5760320 186 {
kenjiArai 0:5b88d5760320 187 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 188 return BD_ERROR_DEVICE_ERROR;
kenjiArai 0:5b88d5760320 189 }
kenjiArai 0:5b88d5760320 190
kenjiArai 0:5b88d5760320 191 MBED_ASSERT(_write_cache);
kenjiArai 0:5b88d5760320 192
kenjiArai 0:5b88d5760320 193 int ret;
kenjiArai 0:5b88d5760320 194
kenjiArai 0:5b88d5760320 195 bd_addr_t aligned_addr = align_down(addr, _bd_program_size);
kenjiArai 0:5b88d5760320 196
kenjiArai 0:5b88d5760320 197 const uint8_t *buf = static_cast <const uint8_t *>(b);
kenjiArai 0:5b88d5760320 198
kenjiArai 0:5b88d5760320 199 // Need to flush if moved to another program unit
kenjiArai 0:5b88d5760320 200 if (aligned_addr != _write_cache_addr) {
kenjiArai 0:5b88d5760320 201 ret = flush();
kenjiArai 0:5b88d5760320 202 if (ret) {
kenjiArai 0:5b88d5760320 203 return ret;
kenjiArai 0:5b88d5760320 204 }
kenjiArai 0:5b88d5760320 205 _write_cache_addr = aligned_addr;
kenjiArai 0:5b88d5760320 206 }
kenjiArai 0:5b88d5760320 207
kenjiArai 0:5b88d5760320 208 // Write logic: Keep data in cache as long as we don't reach the end of the program unit.
kenjiArai 0:5b88d5760320 209 // Otherwise, program to the underlying BD.
kenjiArai 0:5b88d5760320 210 while (size) {
kenjiArai 0:5b88d5760320 211 _write_cache_addr = align_down(addr, _bd_program_size);
kenjiArai 0:5b88d5760320 212 bd_addr_t offs_in_buf = addr - _write_cache_addr;
kenjiArai 0:5b88d5760320 213 bd_size_t chunk;
kenjiArai 0:5b88d5760320 214 if (offs_in_buf) {
kenjiArai 0:5b88d5760320 215 chunk = std::min(_bd_program_size - offs_in_buf, size);
kenjiArai 0:5b88d5760320 216 } else if (size >= _bd_program_size) {
kenjiArai 0:5b88d5760320 217 chunk = align_down(size, _bd_program_size);
kenjiArai 0:5b88d5760320 218 } else {
kenjiArai 0:5b88d5760320 219 chunk = size;
kenjiArai 0:5b88d5760320 220 }
kenjiArai 0:5b88d5760320 221
kenjiArai 0:5b88d5760320 222 const uint8_t *prog_buf;
kenjiArai 0:5b88d5760320 223 if (chunk < _bd_program_size) {
kenjiArai 0:5b88d5760320 224 // If cache not valid, and program doesn't cover an entire unit, it means we need to
kenjiArai 0:5b88d5760320 225 // read it from the underlying BD
kenjiArai 0:5b88d5760320 226 if (!_write_cache_valid) {
kenjiArai 0:5b88d5760320 227 ret = _bd->read(_write_cache, _write_cache_addr, _bd_program_size);
kenjiArai 0:5b88d5760320 228 if (ret) {
kenjiArai 0:5b88d5760320 229 return ret;
kenjiArai 0:5b88d5760320 230 }
kenjiArai 0:5b88d5760320 231 }
kenjiArai 0:5b88d5760320 232 memcpy(_write_cache + offs_in_buf, buf, chunk);
kenjiArai 0:5b88d5760320 233 prog_buf = _write_cache;
kenjiArai 0:5b88d5760320 234 } else {
kenjiArai 0:5b88d5760320 235 prog_buf = buf;
kenjiArai 0:5b88d5760320 236 }
kenjiArai 0:5b88d5760320 237
kenjiArai 0:5b88d5760320 238 // Only program if we reached the end of a program unit
kenjiArai 0:5b88d5760320 239 if (!((offs_in_buf + chunk) % _bd_program_size)) {
kenjiArai 0:5b88d5760320 240 ret = _bd->program(prog_buf, _write_cache_addr, std::max(chunk, _bd_program_size));
kenjiArai 0:5b88d5760320 241 if (ret) {
kenjiArai 0:5b88d5760320 242 return ret;
kenjiArai 0:5b88d5760320 243 }
kenjiArai 0:5b88d5760320 244 ret = _bd->sync();
kenjiArai 0:5b88d5760320 245 if (ret) {
kenjiArai 0:5b88d5760320 246 return ret;
kenjiArai 0:5b88d5760320 247 }
kenjiArai 0:5b88d5760320 248 invalidate_write_cache();
kenjiArai 0:5b88d5760320 249 } else {
kenjiArai 0:5b88d5760320 250 _write_cache_valid = true;
kenjiArai 0:5b88d5760320 251 }
kenjiArai 0:5b88d5760320 252
kenjiArai 0:5b88d5760320 253 buf += chunk;
kenjiArai 0:5b88d5760320 254 addr += chunk;
kenjiArai 0:5b88d5760320 255 size -= chunk;
kenjiArai 0:5b88d5760320 256 }
kenjiArai 0:5b88d5760320 257
kenjiArai 0:5b88d5760320 258 return 0;
kenjiArai 0:5b88d5760320 259 }
kenjiArai 0:5b88d5760320 260
kenjiArai 0:5b88d5760320 261 int BufferedBlockDevice::erase(bd_addr_t addr, bd_size_t size)
kenjiArai 0:5b88d5760320 262 {
kenjiArai 0:5b88d5760320 263 MBED_ASSERT(is_valid_erase(addr, size));
kenjiArai 0:5b88d5760320 264 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 265 return BD_ERROR_DEVICE_ERROR;
kenjiArai 0:5b88d5760320 266 }
kenjiArai 0:5b88d5760320 267
kenjiArai 0:5b88d5760320 268 if ((_write_cache_addr >= addr) && (_write_cache_addr <= addr + size)) {
kenjiArai 0:5b88d5760320 269 invalidate_write_cache();
kenjiArai 0:5b88d5760320 270 }
kenjiArai 0:5b88d5760320 271 return _bd->erase(addr, size);
kenjiArai 0:5b88d5760320 272 }
kenjiArai 0:5b88d5760320 273
kenjiArai 0:5b88d5760320 274 int BufferedBlockDevice::trim(bd_addr_t addr, bd_size_t size)
kenjiArai 0:5b88d5760320 275 {
kenjiArai 0:5b88d5760320 276 MBED_ASSERT(is_valid_erase(addr, size));
kenjiArai 0:5b88d5760320 277 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 278 return BD_ERROR_DEVICE_ERROR;
kenjiArai 0:5b88d5760320 279 }
kenjiArai 0:5b88d5760320 280
kenjiArai 0:5b88d5760320 281 if ((_write_cache_addr >= addr) && (_write_cache_addr <= addr + size)) {
kenjiArai 0:5b88d5760320 282 invalidate_write_cache();
kenjiArai 0:5b88d5760320 283 }
kenjiArai 0:5b88d5760320 284 return _bd->trim(addr, size);
kenjiArai 0:5b88d5760320 285 }
kenjiArai 0:5b88d5760320 286
kenjiArai 0:5b88d5760320 287 bd_size_t BufferedBlockDevice::get_read_size() const
kenjiArai 0:5b88d5760320 288 {
kenjiArai 0:5b88d5760320 289 return 1;
kenjiArai 0:5b88d5760320 290 }
kenjiArai 0:5b88d5760320 291
kenjiArai 0:5b88d5760320 292 bd_size_t BufferedBlockDevice::get_program_size() const
kenjiArai 0:5b88d5760320 293 {
kenjiArai 0:5b88d5760320 294 return 1;
kenjiArai 0:5b88d5760320 295 }
kenjiArai 0:5b88d5760320 296
kenjiArai 0:5b88d5760320 297 bd_size_t BufferedBlockDevice::get_erase_size() const
kenjiArai 0:5b88d5760320 298 {
kenjiArai 0:5b88d5760320 299 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 300 return 0;
kenjiArai 0:5b88d5760320 301 }
kenjiArai 0:5b88d5760320 302
kenjiArai 0:5b88d5760320 303 return _bd->get_erase_size();
kenjiArai 0:5b88d5760320 304 }
kenjiArai 0:5b88d5760320 305
kenjiArai 0:5b88d5760320 306 bd_size_t BufferedBlockDevice::get_erase_size(bd_addr_t addr) const
kenjiArai 0:5b88d5760320 307 {
kenjiArai 0:5b88d5760320 308 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 309 return 0;
kenjiArai 0:5b88d5760320 310 }
kenjiArai 0:5b88d5760320 311
kenjiArai 0:5b88d5760320 312 return _bd->get_erase_size(addr);
kenjiArai 0:5b88d5760320 313 }
kenjiArai 0:5b88d5760320 314
kenjiArai 0:5b88d5760320 315 int BufferedBlockDevice::get_erase_value() const
kenjiArai 0:5b88d5760320 316 {
kenjiArai 0:5b88d5760320 317 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 318 return BD_ERROR_DEVICE_ERROR;
kenjiArai 0:5b88d5760320 319 }
kenjiArai 0:5b88d5760320 320
kenjiArai 0:5b88d5760320 321 return _bd->get_erase_value();
kenjiArai 0:5b88d5760320 322 }
kenjiArai 0:5b88d5760320 323
kenjiArai 0:5b88d5760320 324 bd_size_t BufferedBlockDevice::size() const
kenjiArai 0:5b88d5760320 325 {
kenjiArai 0:5b88d5760320 326 if (!_is_initialized) {
kenjiArai 0:5b88d5760320 327 return 0;
kenjiArai 0:5b88d5760320 328 }
kenjiArai 0:5b88d5760320 329
kenjiArai 0:5b88d5760320 330 return _bd_size;
kenjiArai 0:5b88d5760320 331 }
kenjiArai 0:5b88d5760320 332
kenjiArai 0:5b88d5760320 333 const char *BufferedBlockDevice::get_type() const
kenjiArai 0:5b88d5760320 334 {
kenjiArai 0:5b88d5760320 335 if (_bd != NULL) {
kenjiArai 0:5b88d5760320 336 return _bd->get_type();
kenjiArai 0:5b88d5760320 337 }
kenjiArai 0:5b88d5760320 338
kenjiArai 0:5b88d5760320 339 return NULL;
kenjiArai 0:5b88d5760320 340 }
kenjiArai 0:5b88d5760320 341
kenjiArai 0:5b88d5760320 342 } // namespace mbed