mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
mtd: add module for remapping MTD sectors
This commit is contained in:
parent
cf5356df24
commit
9a430cd682
112
drivers/include/mtd_mapper.h
Normal file
112
drivers/include/mtd_mapper.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Koen Zandberg <koen@bergzand.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_mtd_mapper MTD address mapper
|
||||
* @ingroup drivers_storage
|
||||
* @brief Driver for address remap for flash devices
|
||||
*
|
||||
* This MTD module allows for remapping multiple different regions on a single
|
||||
* MTD device and present them as separate MTD devices. This is similar to
|
||||
* partitions on a hard drive, although this system only allows hardcoded
|
||||
* partitions and lacks a partition table.
|
||||
*
|
||||
* The use case for this module is to be able to split a single MTD device, for
|
||||
* example a SPI NOR flash chip into multiple separate regions which all can
|
||||
* contain their own content or file systems.
|
||||
*
|
||||
* ## Usage
|
||||
*
|
||||
* To use this module include it in your makefile:
|
||||
*
|
||||
* ```
|
||||
* USEMODULE += mtd_mapper
|
||||
* ```
|
||||
*
|
||||
* To define new regions with an existing MTD device the following is required:
|
||||
*
|
||||
* ```
|
||||
* mtd_mapper_parent_t parent = MTD_PARENT_INIT(MTD_0);
|
||||
*
|
||||
* mtd_mapper_region_t region1 = {
|
||||
* .mtd = {
|
||||
* .driver = &mtd_mapper_driver,
|
||||
* .sector_count = SECTOR_COUNT / 2,
|
||||
* .pages_per_sector = PAGE_PER_SECTOR,
|
||||
* .page_size = PAGE_SIZE,
|
||||
* },
|
||||
* .parent = &parent,
|
||||
* .offset = PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT / 2
|
||||
* };
|
||||
*
|
||||
* mtd_dev_t *dev = ®ion.mtd;
|
||||
* ```
|
||||
* The snippet here defines a region within an existing `MTD_0` device of half
|
||||
* the size of `MTD_0` and starting in the middle of the device.
|
||||
*
|
||||
* @warning Please ensure that the different configured regions do not overlap.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @brief Interface definitions for mtd mapper support
|
||||
*
|
||||
* @author Koen Zandberg <koen@bergzand.net>
|
||||
*/
|
||||
|
||||
#ifndef MTD_MAPPER_H
|
||||
#define MTD_MAPPER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "mtd.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Shortcut macro for initializing the members of an
|
||||
* @ref mtd_mapper_parent_t struct
|
||||
*/
|
||||
#define MTD_PARENT_INIT(_parent) \
|
||||
{ \
|
||||
.mtd = _parent, \
|
||||
.lock = MUTEX_INIT, \
|
||||
.init = false, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MTD mapper backing device context
|
||||
*/
|
||||
typedef struct {
|
||||
mtd_dev_t *mtd; /**< Parent MTD device */
|
||||
mutex_t lock; /**< Mutex for guarding the backing device access */
|
||||
bool init; /**< Initialization flag */
|
||||
} mtd_mapper_parent_t;
|
||||
|
||||
/**
|
||||
* @brief MTD mapped region
|
||||
*/
|
||||
typedef struct {
|
||||
mtd_dev_t mtd; /**< MTD context */
|
||||
mtd_mapper_parent_t *parent; /**< MTD mapper parent device */
|
||||
uint32_t offset; /**< Offset address to start this region */
|
||||
} mtd_mapper_region_t;
|
||||
|
||||
/**
|
||||
* @brief Mapper MTD device operations table
|
||||
*/
|
||||
extern const mtd_desc_t mtd_mapper_driver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MTD_MAPPER_H */
|
||||
/** @} */
|
1
drivers/mtd_mapper/Makefile
Normal file
1
drivers/mtd_mapper/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
130
drivers/mtd_mapper/mtd_mapper.c
Normal file
130
drivers/mtd_mapper/mtd_mapper.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Koen Zandberg <koen@bergzand.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_mtd_mapper
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Driver for flash memory remap support
|
||||
*
|
||||
* @author Koen Zandberg <koen@bergzand.net>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "kernel_defines.h"
|
||||
#include "mtd.h"
|
||||
#include "mtd_mapper.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
static void _unlock(mtd_mapper_region_t *region)
|
||||
{
|
||||
mutex_unlock(®ion->parent->lock);
|
||||
}
|
||||
|
||||
static void _lock(mtd_mapper_region_t *region)
|
||||
{
|
||||
mutex_lock(®ion->parent->lock);
|
||||
}
|
||||
|
||||
static uint32_t _region_size(mtd_mapper_region_t *region)
|
||||
{
|
||||
return region->mtd.page_size * region->mtd.pages_per_sector *
|
||||
region->mtd.sector_count;
|
||||
}
|
||||
|
||||
static int _init_target(mtd_mapper_region_t *region)
|
||||
{
|
||||
mtd_mapper_parent_t *parent = region->parent;
|
||||
|
||||
if (!parent->init) {
|
||||
parent->init = true;
|
||||
return mtd_init(parent->mtd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _init(mtd_dev_t *mtd)
|
||||
{
|
||||
|
||||
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
|
||||
mtd_dev_t *backing_mtd = region->parent->mtd;
|
||||
|
||||
/* Configuration sanity checks */
|
||||
assert(backing_mtd->page_size == region->mtd.page_size);
|
||||
assert(backing_mtd->pages_per_sector == region->mtd.pages_per_sector);
|
||||
assert(backing_mtd->sector_count >= region->mtd.sector_count);
|
||||
|
||||
/* offset + region size must not exceed the backing device */
|
||||
assert(region->offset + _region_size(
|
||||
region) <=
|
||||
backing_mtd->pages_per_sector * backing_mtd->sector_count *
|
||||
backing_mtd->page_size);
|
||||
|
||||
_lock(region);
|
||||
int res = _init_target(region);
|
||||
_unlock(region);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _write(mtd_dev_t *mtd, const void *src, uint32_t addr,
|
||||
uint32_t count)
|
||||
{
|
||||
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
|
||||
|
||||
if (addr + count > _region_size(region)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
_lock(region);
|
||||
int res = mtd_write(region->parent->mtd, src, addr + region->offset, count);
|
||||
_unlock(region);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t count)
|
||||
{
|
||||
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
|
||||
|
||||
if (addr + count > _region_size(region)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
_lock(region);
|
||||
int res = mtd_read(region->parent->mtd, dest, addr + region->offset, count);
|
||||
_unlock(region);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _erase(mtd_dev_t *mtd, uint32_t addr, uint32_t count)
|
||||
{
|
||||
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
|
||||
|
||||
if (addr + count > _region_size(region)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
_lock(region);
|
||||
int res = mtd_erase(region->parent->mtd, addr + region->offset, count);
|
||||
_unlock(region);
|
||||
return res;
|
||||
}
|
||||
|
||||
const mtd_desc_t mtd_mapper_driver = {
|
||||
.init = _init,
|
||||
.read = _read,
|
||||
.write = _write,
|
||||
.erase = _erase,
|
||||
};
|
Loading…
Reference in New Issue
Block a user