mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers/mtd_flashpage: implement pagewise API
This commit is contained in:
parent
247b8d0a47
commit
5d5d88b271
@ -43,9 +43,7 @@ extern "C"
|
|||||||
.sector_count = FLASHPAGE_NUMOF, \
|
.sector_count = FLASHPAGE_NUMOF, \
|
||||||
.pages_per_sector = _pages_per_sector, \
|
.pages_per_sector = _pages_per_sector, \
|
||||||
.page_size = FLASHPAGE_SIZE / _pages_per_sector, \
|
.page_size = FLASHPAGE_SIZE / _pages_per_sector, \
|
||||||
.write_size = FLASHPAGE_WRITE_BLOCK_SIZE >= FLASHPAGE_WRITE_BLOCK_ALIGNMENT \
|
.write_size = 1 \
|
||||||
? FLASHPAGE_WRITE_BLOCK_SIZE \
|
|
||||||
: FLASHPAGE_WRITE_BLOCK_ALIGNMENT, \
|
|
||||||
}, \
|
}, \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +57,9 @@ extern const mtd_desc_t mtd_flashpage_driver;
|
|||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mtd_dev_t base; /**< MTD generic device */
|
mtd_dev_t base; /**< MTD generic device */
|
||||||
|
uint32_t offset; /**< Offset in terms of MTD pages, which must comprise
|
||||||
|
a whole number of sectors from the start of the
|
||||||
|
flash */
|
||||||
} mtd_flashpage_t;
|
} mtd_flashpage_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* @brief Implementation for the flashpage memory driver
|
* @brief Implementation for the flashpage memory driver
|
||||||
*
|
*
|
||||||
* @author Vincent Dupont <vincent@otakeys.com>
|
* @author Vincent Dupont <vincent@otakeys.com>
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
* @author Fabian Hüßler <fabian.huessler@st.ovgu.de>
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -26,23 +28,38 @@
|
|||||||
#include "architecture.h"
|
#include "architecture.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "cpu_conf.h"
|
#include "cpu_conf.h"
|
||||||
|
#include "macros/utils.h"
|
||||||
#include "mtd_flashpage.h"
|
#include "mtd_flashpage.h"
|
||||||
#include "periph/flashpage.h"
|
#include "periph/flashpage.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG 0
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
#define MTD_FLASHPAGE_END_ADDR ((uint32_t) CPU_FLASH_BASE + (FLASHPAGE_NUMOF * FLASHPAGE_SIZE))
|
#define MTD_FLASHPAGE_END_ADDR ((uint32_t) CPU_FLASH_BASE + (FLASHPAGE_NUMOF * FLASHPAGE_SIZE))
|
||||||
|
|
||||||
static int _init(mtd_dev_t *dev)
|
static int _init(mtd_dev_t *dev)
|
||||||
{
|
{
|
||||||
(void)dev;
|
mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base);
|
||||||
|
(void)super;
|
||||||
assert(dev->pages_per_sector * dev->page_size == FLASHPAGE_SIZE);
|
assert(dev->pages_per_sector * dev->page_size == FLASHPAGE_SIZE);
|
||||||
|
assert(!(super->offset % dev->pages_per_sector));
|
||||||
|
|
||||||
|
assert((int)flashpage_addr(super->offset / dev->pages_per_sector) >= (int)CPU_FLASH_BASE);
|
||||||
|
assert((uintptr_t)flashpage_addr(super->offset / dev->pages_per_sector)
|
||||||
|
+ dev->pages_per_sector * dev->page_size * dev->sector_count <= MTD_FLASHPAGE_END_ADDR);
|
||||||
|
assert((uintptr_t)flashpage_addr(super->offset / dev->pages_per_sector)
|
||||||
|
+ dev->pages_per_sector * dev->page_size * dev->sector_count > CPU_FLASH_BASE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _read(mtd_dev_t *dev, void *buf, uint32_t addr, uint32_t size)
|
static int _read(mtd_dev_t *dev, void *buf, uint32_t addr, uint32_t size)
|
||||||
{
|
{
|
||||||
assert(addr < MTD_FLASHPAGE_END_ADDR);
|
mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base);
|
||||||
|
|
||||||
(void)dev;
|
addr += (uintptr_t)flashpage_addr(super->offset);
|
||||||
|
|
||||||
|
DEBUG("flashpage: read %"PRIu32" bytes from 0x%"PRIx32" to %p\n", size, addr, buf);
|
||||||
|
assert(addr < MTD_FLASHPAGE_END_ADDR);
|
||||||
|
|
||||||
#ifndef CPU_HAS_UNALIGNED_ACCESS
|
#ifndef CPU_HAS_UNALIGNED_ACCESS
|
||||||
if (addr % sizeof(uword_t)) {
|
if (addr % sizeof(uword_t)) {
|
||||||
@ -56,9 +73,49 @@ static int _read(mtd_dev_t *dev, void *buf, uint32_t addr, uint32_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _read_page(mtd_dev_t *dev, void *buf, uint32_t page,
|
||||||
|
uint32_t offset, uint32_t size)
|
||||||
|
{
|
||||||
|
mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base);
|
||||||
|
|
||||||
|
assert(page + super->offset >= page);
|
||||||
|
page += super->offset;
|
||||||
|
|
||||||
|
/* mtd flashpage maps multiple pages to one virtual sector for unknown reason */
|
||||||
|
uint32_t fpage = page / dev->pages_per_sector;
|
||||||
|
offset += (page % dev->pages_per_sector) * dev->page_size;
|
||||||
|
uintptr_t addr = (uintptr_t)flashpage_addr(fpage);
|
||||||
|
|
||||||
|
addr += offset;
|
||||||
|
|
||||||
|
DEBUG("flashpage: read %"PRIu32" bytes from %p to %p\n", size, (void *)addr, buf);
|
||||||
|
|
||||||
|
#ifndef CPU_HAS_UNALIGNED_ACCESS
|
||||||
|
if (addr % sizeof(uword_t)) {
|
||||||
|
uword_t tmp;
|
||||||
|
|
||||||
|
offset = addr % sizeof(uword_t);
|
||||||
|
size = MIN(size, sizeof(uword_t) - offset);
|
||||||
|
|
||||||
|
DEBUG("flashpage: read %"PRIu32" unaligned bytes\n", size);
|
||||||
|
|
||||||
|
memcpy(&tmp, (uint8_t *)addr - offset, sizeof(tmp));
|
||||||
|
memcpy(buf, (uint8_t *)&tmp + offset, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memcpy(buf, (void *)addr, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
static int _write(mtd_dev_t *dev, const void *buf, uint32_t addr, uint32_t size)
|
static int _write(mtd_dev_t *dev, const void *buf, uint32_t addr, uint32_t size)
|
||||||
{
|
{
|
||||||
(void)dev;
|
mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base);
|
||||||
|
|
||||||
|
addr += (uintptr_t)flashpage_addr(super->offset);
|
||||||
|
|
||||||
|
DEBUG("flashpage: write %"PRIu32" bytes from %p to 0x%"PRIx32"\n", size, buf, addr);
|
||||||
|
|
||||||
#ifndef CPU_HAS_UNALIGNED_ACCESS
|
#ifndef CPU_HAS_UNALIGNED_ACCESS
|
||||||
if ((uintptr_t)buf % sizeof(uword_t)) {
|
if ((uintptr_t)buf % sizeof(uword_t)) {
|
||||||
@ -81,24 +138,63 @@ static int _write(mtd_dev_t *dev, const void *buf, uint32_t addr, uint32_t size)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size)
|
static int _write_page(mtd_dev_t *dev, const void *buf, uint32_t page, uint32_t offset,
|
||||||
|
uint32_t size)
|
||||||
{
|
{
|
||||||
size_t sector_size = dev->page_size * dev->pages_per_sector;
|
mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base);
|
||||||
|
|
||||||
if (size % sector_size) {
|
assert(page + super->offset >= page);
|
||||||
return -EOVERFLOW;
|
|
||||||
}
|
page += super->offset;
|
||||||
if (addr + size > MTD_FLASHPAGE_END_ADDR) {
|
|
||||||
return -EOVERFLOW;
|
/* mtd flashpage maps multiple pages to one virtual sector for unknown reason */
|
||||||
}
|
uint32_t fpage = page / dev->pages_per_sector;
|
||||||
if (addr % sector_size) {
|
offset += (page % dev->pages_per_sector) * dev->page_size;
|
||||||
return -EOVERFLOW;
|
uintptr_t addr = (uintptr_t)flashpage_addr(fpage);
|
||||||
|
|
||||||
|
addr += offset;
|
||||||
|
|
||||||
|
DEBUG("flashpage: write %"PRIu32" bytes from %p to %p\n", size, buf, (void *)addr);
|
||||||
|
|
||||||
|
size = MIN(flashpage_size(fpage) - offset, size);
|
||||||
|
|
||||||
|
if ((addr % FLASHPAGE_WRITE_BLOCK_ALIGNMENT) || (size < FLASHPAGE_WRITE_BLOCK_SIZE) ||
|
||||||
|
((uintptr_t)buf % FLASHPAGE_WRITE_BLOCK_ALIGNMENT)) {
|
||||||
|
uint8_t tmp[FLASHPAGE_WRITE_BLOCK_SIZE]
|
||||||
|
__attribute__ ((aligned (FLASHPAGE_WRITE_BLOCK_ALIGNMENT)));
|
||||||
|
|
||||||
|
offset = addr % FLASHPAGE_WRITE_BLOCK_ALIGNMENT;
|
||||||
|
size = MIN(size, FLASHPAGE_WRITE_BLOCK_ALIGNMENT - offset);
|
||||||
|
|
||||||
|
DEBUG("flashpage: write %"PRIu32" unaligned bytes\n", size);
|
||||||
|
|
||||||
|
memcpy(&tmp[0], (uint8_t *)addr - offset, sizeof(tmp));
|
||||||
|
memcpy(&tmp[offset], buf, size);
|
||||||
|
|
||||||
|
flashpage_write((uint8_t *)addr - offset, tmp, sizeof(tmp));
|
||||||
|
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uword_t dst_addr = addr;
|
/* don't write less than the write block size */
|
||||||
|
size &= ~(FLASHPAGE_WRITE_BLOCK_SIZE - 1);
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i += sector_size) {
|
flashpage_write((void *)addr, buf, size);
|
||||||
flashpage_erase(flashpage_page((void *)(dst_addr + i)));
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _erase_sector(mtd_dev_t *dev, uint32_t sector, uint32_t count)
|
||||||
|
{
|
||||||
|
mtd_flashpage_t *super = container_of(dev, mtd_flashpage_t, base);
|
||||||
|
|
||||||
|
if (sector + (super->offset / dev->pages_per_sector) < sector) {
|
||||||
|
return -EOVERFLOW;
|
||||||
|
}
|
||||||
|
sector += (super->offset / dev->pages_per_sector);
|
||||||
|
|
||||||
|
while (count--) {
|
||||||
|
DEBUG("flashpage: erase sector %"PRIu32"\n", sector);
|
||||||
|
flashpage_erase(sector++);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -107,6 +203,8 @@ int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size)
|
|||||||
const mtd_desc_t mtd_flashpage_driver = {
|
const mtd_desc_t mtd_flashpage_driver = {
|
||||||
.init = _init,
|
.init = _init,
|
||||||
.read = _read,
|
.read = _read,
|
||||||
|
.read_page = _read_page,
|
||||||
.write = _write,
|
.write = _write,
|
||||||
.erase = _erase,
|
.write_page = _write_page,
|
||||||
|
.erase_sector = _erase_sector,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user