diff --git a/_targets/Makefile.riscv64-noelv b/_targets/Makefile.riscv64-noelv index 49653f5d..f50d8062 100644 --- a/_targets/Makefile.riscv64-noelv +++ b/_targets/Makefile.riscv64-noelv @@ -6,4 +6,4 @@ # Copyright 2024 Phoenix Systems # -DEFAULT_COMPONENTS := grlib-uart +DEFAULT_COMPONENTS := grlib-uart flashdrv diff --git a/_targets/Makefile.sparcv8leon-gr740 b/_targets/Makefile.sparcv8leon-gr740 index 73e9ac4e..60884d8b 100644 --- a/_targets/Makefile.sparcv8leon-gr740 +++ b/_targets/Makefile.sparcv8leon-gr740 @@ -3,7 +3,7 @@ # # sparcv8leon-gr740 drivers # -# Copyright 2024 Phoenix Systems +# Copyright 2025 Phoenix Systems # -DEFAULT_COMPONENTS := grlib-multi ftmctrl-flash +DEFAULT_COMPONENTS := grlib-multi flashdrv diff --git a/storage/flashdrv/Makefile b/storage/flashdrv/Makefile new file mode 100644 index 00000000..b8025969 --- /dev/null +++ b/storage/flashdrv/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for Phoenix-RTOS ftmctrl-flash driver +# +# Copyright 2023-2025 Phoenix Systems +# + +NAME := flashdrv +LOCAL_SRCS := common.c flashsrv.c +DEP_LIBS := libftmctrl libspimctrl +LIBS := libjffs2 libstorage libmtd libptable libcache + +include $(binary.mk) diff --git a/storage/flashdrv/common.c b/storage/flashdrv/common.c new file mode 100644 index 00000000..d8015a03 --- /dev/null +++ b/storage/flashdrv/common.c @@ -0,0 +1,28 @@ +/* + * Phoenix-RTOS + * + * GRLIB FTMCTRL Flash driver + * + * Common auxiliary functions + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include + + +off_t common_getSectorOffset(size_t sectorsz, off_t offs) +{ + return offs & ~(sectorsz - 1); +} + + +bool common_isValidAddress(size_t memsz, off_t offs, size_t len) +{ + return ((offs < memsz) && ((offs + len) <= memsz)); +} diff --git a/storage/flashdrv/drv/grlib-ftmctrl/Makefile b/storage/flashdrv/drv/grlib-ftmctrl/Makefile new file mode 100644 index 00000000..40ffc980 --- /dev/null +++ b/storage/flashdrv/drv/grlib-ftmctrl/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for Phoenix-RTOS libftmctrl driver +# +# Copyright 2025 Phoenix Systems +# + +NAME := libftmctrl +LOCAL_SRCS := amd-flash.c flashdrv.c flash.c intel-flash.c + +include $(static-lib.mk) diff --git a/storage/ftmctrl-flash/amd-flash.c b/storage/flashdrv/drv/grlib-ftmctrl/amd-flash.c similarity index 96% rename from storage/ftmctrl-flash/amd-flash.c rename to storage/flashdrv/drv/grlib-ftmctrl/amd-flash.c index 0cb33d0d..4b3496e3 100644 --- a/storage/ftmctrl-flash/amd-flash.c +++ b/storage/flashdrv/drv/grlib-ftmctrl/amd-flash.c @@ -5,7 +5,7 @@ * * AMD command set flash interface * - * Copyright 2024 Phoenix Systems + * Copyright 2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -115,7 +115,7 @@ static void amd_exitQuery(volatile uint8_t *base) } -void amd_register(void) +void ftmctrl_amd_register(void) { static const flash_ops_t ops = { .statusRead = amd_statusRead, @@ -143,6 +143,6 @@ void amd_register(void) }; for (size_t i = 0; i < (sizeof(amd_devices) / sizeof(amd_devices[0])); ++i) { - flash_register(&amd_devices[i]); + ftmctrl_flash_register(&amd_devices[i]); } } diff --git a/storage/ftmctrl-flash/cmds.h b/storage/flashdrv/drv/grlib-ftmctrl/cmds.h similarity index 93% rename from storage/ftmctrl-flash/cmds.h rename to storage/flashdrv/drv/grlib-ftmctrl/cmds.h index a595d4cb..a304140e 100644 --- a/storage/ftmctrl-flash/cmds.h +++ b/storage/flashdrv/drv/grlib-ftmctrl/cmds.h @@ -5,7 +5,7 @@ * * Flash commands * - * Copyright 2024 Phoenix Systems + * Copyright 2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -13,8 +13,8 @@ * %LICENSE% */ -#ifndef _CMDS_H_ -#define _CMDS_H_ +#ifndef _FTMCTRL_CMDS_H_ +#define _FTMCTRL_CMDS_H_ /* Common flash commands */ diff --git a/storage/ftmctrl-flash/flash.c b/storage/flashdrv/drv/grlib-ftmctrl/flash.c similarity index 86% rename from storage/ftmctrl-flash/flash.c rename to storage/flashdrv/drv/grlib-ftmctrl/flash.c index 8cc3ddbb..12191861 100644 --- a/storage/ftmctrl-flash/flash.c +++ b/storage/flashdrv/drv/grlib-ftmctrl/flash.c @@ -3,7 +3,7 @@ * * GRLIB FTMCTRL Flash driver * - * Copyright 2023, 2024 Phoenix Systems + * Copyright 2023-2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -22,6 +22,8 @@ #include #include +#include + #include "cmds.h" #include "flash.h" #include "flashdrv.h" @@ -111,7 +113,7 @@ static uint16_t flash_deserialize16(uint16_t value) } -int flash_writeBuffer(const struct _storage_devCtx_t *ctx, off_t offs, const uint8_t *data, size_t len, time_t timeout) +int ftmctrl_flash_writeBuffer(const struct _storage_devCtx_t *ctx, off_t offs, const uint8_t *data, size_t len, time_t timeout) { uint16_t val; const int portWidth = ftmctrl_portWidth(ctx->ftmctrl); @@ -139,10 +141,10 @@ int flash_writeBuffer(const struct _storage_devCtx_t *ctx, off_t offs, const uin data += i; if (len == 0) { - return EOK; + return 0; } - off_t sectorOffs = flash_getSectorOffset(ctx, offs); + off_t sectorOffs = common_getSectorOffset(ctx->sectorsz, offs); ctx->dev->ops->issueWriteBuffer(common.base, sectorOffs, offs, len); @@ -196,7 +198,7 @@ int flash_writeBuffer(const struct _storage_devCtx_t *ctx, off_t offs, const uin } -int flash_sectorErase(const struct _storage_devCtx_t *ctx, off_t sectorOffs, time_t timeout) +int ftmctrl_flash_sectorErase(const struct _storage_devCtx_t *ctx, off_t sectorOffs, time_t timeout) { ctx->dev->ops->issueSectorErase(common.base, sectorOffs); @@ -230,7 +232,7 @@ int flash_sectorErase(const struct _storage_devCtx_t *ctx, off_t sectorOffs, tim } -int flash_chipErase(const struct _storage_devCtx_t *ctx, time_t timeout) +int ftmctrl_flash_chipErase(const struct _storage_devCtx_t *ctx, time_t timeout) { if (ctx->dev->ops->issueChipErase == NULL) { return -ENOSYS; @@ -248,7 +250,7 @@ int flash_chipErase(const struct _storage_devCtx_t *ctx, time_t timeout) } -void flash_read(const struct _storage_devCtx_t *ctx, off_t offs, void *buff, size_t len) +void ftmctrl_flash_read(const struct _storage_devCtx_t *ctx, off_t offs, void *buff, size_t len) { ctx->dev->ops->issueReset(common.base); @@ -256,7 +258,7 @@ void flash_read(const struct _storage_devCtx_t *ctx, off_t offs, void *buff, siz } -void flash_printInfo(const struct _storage_devCtx_t *ctx) +void ftmctrl_flash_printInfo(const struct _storage_devCtx_t *ctx) { LOG("configured %s %u MB flash", ctx->dev->name, CFI_SIZE(ctx->cfi.chipSz) / (1024 * 1024)); } @@ -331,13 +333,13 @@ static const flash_dev_t *flash_query(cfi_info_t *cfi) } -int flash_init(struct _storage_devCtx_t *ctx) +int ftmctrl_flash_init(struct _storage_devCtx_t *ctx, addr_t flashBase) { - amd_register(); - intel_register(); + ftmctrl_amd_register(); + ftmctrl_intel_register(); /* Temporarily map one page on flash as uncached to be able to read status */ - common.base = mmap(NULL, _PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, ADDR_FLASH); + common.base = mmap(NULL, _PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, flashBase); if (common.base == MAP_FAILED) { LOG_ERROR("failed to map flash"); return -ENOMEM; @@ -356,21 +358,28 @@ int flash_init(struct _storage_devCtx_t *ctx) ctx->sectorsz = CFI_SIZE(ctx->cfi.chipSz) / (ctx->cfi.regions[0].count + 1); /* Map entire flash */ - common.base = mmap(NULL, CFI_SIZE(ctx->cfi.chipSz), PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, ADDR_FLASH); + common.base = mmap(NULL, CFI_SIZE(ctx->cfi.chipSz), PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, flashBase); if (common.base == MAP_FAILED) { LOG_ERROR("failed to map flash"); return -ENOMEM; } - return EOK; + return 0; +} + + +void ftmctrl_flash_destroy(struct _storage_devCtx_t *ctx) +{ + (void)munmap((void *)common.base, CFI_SIZE(ctx->cfi.chipSz)); } -void flash_register(const flash_dev_t *dev) +void ftmctrl_flash_register(const flash_dev_t *dev) { if (common.nmodels >= FLASH_DEVICES) { LOG("Too many flashes: %s not registered. Please increase FLASH_DEVICES", dev->name); - return; } - common.devs[common.nmodels++] = dev; + else { + common.devs[common.nmodels++] = dev; + } } diff --git a/storage/ftmctrl-flash/flash.h b/storage/flashdrv/drv/grlib-ftmctrl/flash.h similarity index 57% rename from storage/ftmctrl-flash/flash.h rename to storage/flashdrv/drv/grlib-ftmctrl/flash.h index fd918411..c146d8b7 100644 --- a/storage/ftmctrl-flash/flash.h +++ b/storage/flashdrv/drv/grlib-ftmctrl/flash.h @@ -5,7 +5,7 @@ * * Internal flash functions * - * Copyright 2023, 2024 Phoenix Systems + * Copyright 2023-2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -13,8 +13,8 @@ * %LICENSE% */ -#ifndef _FLASH_H_ -#define _FLASH_H_ +#ifndef _FTMCTRL_FLASH_H_ +#define _FTMCTRL_FLASH_H_ #include @@ -47,37 +47,34 @@ typedef struct _flash_dev_t { } flash_dev_t; -static inline off_t flash_getSectorOffset(const struct _storage_devCtx_t *ctx, off_t offs) -{ - return offs & ~(ctx->sectorsz - 1); -} +int ftmctrl_flash_writeBuffer(const struct _storage_devCtx_t *ctx, off_t offs, const uint8_t *data, size_t len, time_t timeout); +/* Timeout in us */ +int ftmctrl_flash_sectorErase(const struct _storage_devCtx_t *ctx, off_t sectorOffs, time_t timeout); -int flash_writeBuffer(const struct _storage_devCtx_t *ctx, off_t offs, const uint8_t *data, size_t len, time_t timeout); -/* Timeout in us */ -int flash_sectorErase(const struct _storage_devCtx_t *ctx, off_t sectorOffs, time_t timeout); +int ftmctrl_flash_chipErase(const struct _storage_devCtx_t *ctx, time_t timeout); -int flash_chipErase(const struct _storage_devCtx_t *ctx, time_t timeout); +void ftmctrl_flash_read(const struct _storage_devCtx_t *ctx, off_t offs, void *buff, size_t len); -void flash_read(const struct _storage_devCtx_t *ctx, off_t offs, void *buff, size_t len); +void ftmctrl_flash_printInfo(const struct _storage_devCtx_t *ctx); -void flash_printInfo(const struct _storage_devCtx_t *ctx); +int ftmctrl_flash_init(struct _storage_devCtx_t *ctx, addr_t flashBase); -int flash_init(struct _storage_devCtx_t *ctx); +void ftmctrl_flash_destroy(struct _storage_devCtx_t *ctx); -void flash_register(const flash_dev_t *dev); +void ftmctrl_flash_register(const flash_dev_t *dev); -void amd_register(void); +void ftmctrl_amd_register(void); -void intel_register(void); +void ftmctrl_intel_register(void); #endif diff --git a/storage/ftmctrl-flash/flashdrv.c b/storage/flashdrv/drv/grlib-ftmctrl/flashdrv.c similarity index 60% rename from storage/ftmctrl-flash/flashdrv.c rename to storage/flashdrv/drv/grlib-ftmctrl/flashdrv.c index f384ac3c..ed534a1c 100644 --- a/storage/ftmctrl-flash/flashdrv.c +++ b/storage/flashdrv/drv/grlib-ftmctrl/flashdrv.c @@ -3,7 +3,7 @@ * * GRLIB FTMCTRL Flash driver * - * Copyright 2023 Phoenix Systems + * Copyright 2023-2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -20,6 +20,10 @@ #include #include +#include +#include + +#include "flashdrv.h" #include "flash.h" #include "ftmctrl.h" @@ -28,42 +32,29 @@ #define LIBCACHE_POLICY LIBCACHE_WRITE_THROUGH -/* Helper functions */ - - -static int fdrv_isValidAddress(size_t memsz, off_t offs, size_t len) -{ - if ((offs < memsz) && ((offs + len) <= memsz)) { - return 1; - } - - return 0; -} - - /* MTD interface */ static int _flashdrv_mtdRead(storage_t *strg, off_t offs, void *buff, size_t len, size_t *retlen) { struct _storage_devCtx_t *ctx = strg->dev->ctx; - if (fdrv_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len) == 0) { + if (!common_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len)) { *retlen = 0; return -EINVAL; } if (len == 0u) { *retlen = 0; - return EOK; + return 0; } ftmctrl_WrEn(ctx->ftmctrl); - flash_read(ctx, offs, buff, len); + ftmctrl_flash_read(ctx, offs, buff, len); ftmctrl_WrDis(ctx->ftmctrl); *retlen = len; - return EOK; + return 0; } @@ -103,27 +94,27 @@ static int flashdrv_mtdRead(storage_t *strg, off_t offs, void *buff, size_t len, static int _flashdrv_mtdWrite(storage_t *strg, off_t offs, const void *buff, size_t len, size_t *retlen) { struct _storage_devCtx_t *ctx = strg->dev->ctx; - if (fdrv_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len) == 0) { + if (!common_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len)) { *retlen = 0; return -EINVAL; } if (len == 0u) { *retlen = 0; - return EOK; + return 0; } const uint8_t *src = buff; size_t doneBytes = 0; - int res = EOK; + int res = 0; const size_t writeBuffsz = strg->dev->mtd->writeBuffsz; while (doneBytes < len) { size_t chunk = min(writeBuffsz - (offs % writeBuffsz), len - doneBytes); ftmctrl_WrEn(ctx->ftmctrl); - res = flash_writeBuffer(ctx, offs, src, chunk, CFI_TIMEOUT_MAX_PROGRAM(ctx->cfi.toutTypical.bufWrite, ctx->cfi.toutMax.bufWrite)); + res = ftmctrl_flash_writeBuffer(ctx, offs, src, chunk, CFI_TIMEOUT_MAX_PROGRAM(ctx->cfi.toutTypical.bufWrite, ctx->cfi.toutMax.bufWrite) * 2); ftmctrl_WrDis(ctx->ftmctrl); if (res < 0) { @@ -185,12 +176,12 @@ static int flashdrv_mtdErase(storage_t *strg, off_t offs, size_t len) } struct _storage_devCtx_t *ctx = strg->dev->ctx; - if ((fdrv_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len) == 0) || ((offs & (ctx->sectorsz - 1)) != 0) || (len % ctx->sectorsz != 0)) { + if (!common_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len) || ((offs & (ctx->sectorsz - 1)) != 0) || (len % ctx->sectorsz != 0)) { return -EINVAL; } if (len == 0u) { - return EOK; + return 0; } mutexLock(ctx->lock); @@ -200,18 +191,18 @@ static int flashdrv_mtdErase(storage_t *strg, off_t offs, size_t len) int res = -ENOSYS; if ((offs == 0) && (len == CFI_SIZE(ctx->cfi.chipSz))) { TRACE("erasing entire memory"); - res = flash_chipErase(ctx, CFI_TIMEOUT_MAX_ERASE(ctx->cfi.toutTypical.chipErase, ctx->cfi.toutMax.chipErase)); + res = ftmctrl_flash_chipErase(ctx, CFI_TIMEOUT_MAX_ERASE(ctx->cfi.toutTypical.chipErase, ctx->cfi.toutMax.chipErase)); end = CFI_SIZE(ctx->cfi.chipSz); } else { - end = flash_getSectorOffset(ctx, offs + len + ctx->sectorsz - 1u); - TRACE("erasing sectors from 0x%llx to 0x%llx", offs, end); + end = common_getSectorOffset(ctx->sectorsz, offs + len + ctx->sectorsz - 1u); + TRACE("erasing sectors from 0x%jx to 0x%jx", (uintmax_t)offs, (uintmax_t)end); } if (res == -ENOSYS) { off_t secOffs = offs; while (secOffs < end) { - res = flash_sectorErase(ctx, secOffs, CFI_TIMEOUT_MAX_ERASE(ctx->cfi.toutTypical.blkErase, ctx->cfi.toutMax.blkErase)); + res = ftmctrl_flash_sectorErase(ctx, secOffs, CFI_TIMEOUT_MAX_ERASE(ctx->cfi.toutTypical.blkErase, ctx->cfi.toutMax.blkErase) * 2); if (res < 0) { break; } @@ -227,20 +218,6 @@ static int flashdrv_mtdErase(storage_t *strg, off_t offs, size_t len) } -static void flashdrv_mtdSync(storage_t *strg) -{ - if ((strg == NULL) || (strg->dev == NULL) || (strg->dev->ctx == NULL)) { - return; - } - - struct _storage_devCtx_t *ctx = strg->dev->ctx; - - mutexLock(ctx->lock); - cache_flush(ctx->cache, 0, CFI_SIZE(ctx->cfi.chipSz)); - mutexUnlock(ctx->lock); -} - - static const storage_mtdops_t mtdOps = { .erase = flashdrv_mtdErase, .unPoint = NULL, @@ -251,7 +228,7 @@ static const storage_mtdops_t mtdOps = { .meta_read = NULL, .meta_write = NULL, - .sync = flashdrv_mtdSync, + .sync = NULL, .lock = NULL, .unLock = NULL, .isLocked = NULL, @@ -267,26 +244,44 @@ static const storage_mtdops_t mtdOps = { }; -const storage_mtdops_t *flashdrv_getMtdOps(void) +static void flashdrv_destroy(storage_t *strg) { - return &mtdOps; + if (strg == NULL) { + return; + } + + if (strg->dev != NULL) { + if (strg->dev->ctx != NULL) { + if (strg->dev->ctx->cache != NULL) { + cache_deinit(strg->dev->ctx->cache); + } + (void)resourceDestroy(strg->dev->ctx->lock); + (void)munmap(strg->dev->ctx->ftmctrl, _PAGE_SIZE); + ftmctrl_flash_destroy(strg->dev->ctx); + } + free(strg->dev->ctx); + free(strg->dev->mtd); + free(strg->dev); + } + free(strg); + strg = NULL; } -struct _storage_devCtx_t *flashdrv_contextInit(void) +static storage_t *flashdrv_init(addr_t mctrlBase, addr_t flashBase) { struct _storage_devCtx_t *ctx = malloc(sizeof(struct _storage_devCtx_t)); if (ctx == NULL) { return NULL; } - ctx->ftmctrl = mmap(NULL, _PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, FTMCTRL_BASE); + ctx->ftmctrl = mmap(NULL, _PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, mctrlBase); if (ctx->ftmctrl == MAP_FAILED) { free(ctx); return NULL; } ftmctrl_WrEn(ctx->ftmctrl); - int res = flash_init(ctx); + int res = ftmctrl_flash_init(ctx, flashBase); ftmctrl_WrDis(ctx->ftmctrl); if (res < 0) { (void)munmap(ctx->ftmctrl, _PAGE_SIZE); @@ -296,18 +291,59 @@ struct _storage_devCtx_t *flashdrv_contextInit(void) if (mutexCreate(&ctx->lock) < 0) { (void)munmap(ctx->ftmctrl, _PAGE_SIZE); + ftmctrl_flash_destroy(ctx); free(ctx); return NULL; } - flash_printInfo(ctx); + storage_t *strg = calloc(1, sizeof(storage_t)); + if (strg == NULL) { + (void)munmap(ctx->ftmctrl, _PAGE_SIZE); + ftmctrl_flash_destroy(ctx); + free(ctx); + return NULL; + } - return ctx; -} + strg->start = 0; + strg->size = CFI_SIZE(ctx->cfi.chipSz); + strg->dev = calloc(1, sizeof(storage_dev_t)); + if (strg->dev == NULL) { + (void)munmap(ctx->ftmctrl, _PAGE_SIZE); + ftmctrl_flash_destroy(ctx); + free(ctx); + free(strg); + return NULL; + } -int flashdrv_cacheInit(storage_t *strg) -{ + /* Assign device context */ + strg->dev->ctx = ctx; + + storage_mtd_t *mtd = calloc(1, sizeof(storage_mtd_t)); + if (mtd == NULL) { + flashdrv_destroy(strg); + return NULL; + } + + /* MTD interface */ + mtd->ops = &mtdOps; + mtd->type = mtd_norFlash; + mtd->name = ctx->dev->name; + mtd->metaSize = 0; + mtd->oobSize = 0; + mtd->oobAvail = 0; + + uint8_t shift = ((ctx->dev->chipWidth == 16) && (ftmctrl_portWidth(ctx->ftmctrl) == 8)) ? 1 : 0; + mtd->writeBuffsz = CFI_SIZE(ctx->cfi.bufSz) >> shift; + mtd->writesz = 1; + mtd->erasesz = ctx->sectorsz; + + strg->dev->mtd = mtd; + + /* No block device interface */ + strg->dev->blk = NULL; + + /* Initialize cache */ cache_ops_t cacheOps = { .readCb = _flashdrv_mtdReadCb, .writeCb = _flashdrv_mtdWriteCb, @@ -315,20 +351,24 @@ int flashdrv_cacheInit(storage_t *strg) }; strg->dev->ctx->cache = cache_init(strg->size, strg->dev->mtd->writeBuffsz, LIBCACHE_LINECNT, &cacheOps); if (strg->dev->ctx->cache == NULL) { - return -ENOMEM; + flashdrv_destroy(strg); + return NULL; } strg->dev->ctx->cacheCtx.strg = strg; - return 0; + ftmctrl_flash_printInfo(ctx); + + return strg; } -void flashdrv_contextDestroy(struct _storage_devCtx_t *ctx) +void __attribute__((constructor)) ftmctrl_register(void) { - if (ctx->cache != NULL) { - cache_deinit(ctx->cache); - } - (void)resourceDestroy(ctx->lock); - (void)munmap(ctx->ftmctrl, _PAGE_SIZE); - free(ctx); + static const struct flash_driver ftmctrl = { + .name = "ftmctrl", + .init = flashdrv_init, + .destroy = flashdrv_destroy, + }; + + flashsrv_register(&ftmctrl); } diff --git a/storage/flashdrv/drv/grlib-ftmctrl/flashdrv.h b/storage/flashdrv/drv/grlib-ftmctrl/flashdrv.h new file mode 100644 index 00000000..b0fbac32 --- /dev/null +++ b/storage/flashdrv/drv/grlib-ftmctrl/flashdrv.h @@ -0,0 +1,44 @@ +/* + * Phoenix-RTOS + * + * GRLIB FTMCTRL Flash driver + * + * Copyright 2023-2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _FTMCTRL_FLASHDRV_H_ +#define _FTMCTRL_FLASHDRV_H_ + + +#include +#include +#include +#include + + +struct cache_devCtx_s { + struct _storage_t *strg; +}; + + +struct _storage_devCtx_t { + cfi_info_t cfi; + const struct _flash_dev_t *dev; + + void *ftmctrl; + + handle_t lock; + size_t sectorsz; + + cachectx_t *cache; + cache_devCtx_t cacheCtx; +}; + + +#endif diff --git a/storage/ftmctrl-flash/ftmctrl.h b/storage/flashdrv/drv/grlib-ftmctrl/ftmctrl.h similarity index 94% rename from storage/ftmctrl-flash/ftmctrl.h rename to storage/flashdrv/drv/grlib-ftmctrl/ftmctrl.h index 779de196..59e57fe8 100644 --- a/storage/ftmctrl-flash/ftmctrl.h +++ b/storage/flashdrv/drv/grlib-ftmctrl/ftmctrl.h @@ -5,7 +5,7 @@ * * FTMCTRL routines * - * Copyright 2023 Phoenix Systems + * Copyright 2023-2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. diff --git a/storage/ftmctrl-flash/intel-flash.c b/storage/flashdrv/drv/grlib-ftmctrl/intel-flash.c similarity index 94% rename from storage/ftmctrl-flash/intel-flash.c rename to storage/flashdrv/drv/grlib-ftmctrl/intel-flash.c index 70081521..9e26a96d 100644 --- a/storage/ftmctrl-flash/intel-flash.c +++ b/storage/flashdrv/drv/grlib-ftmctrl/intel-flash.c @@ -5,7 +5,7 @@ * * Intel command set flash interface * - * Copyright 2024 Phoenix Systems + * Copyright 2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -16,6 +16,8 @@ #include "cmds.h" #include "flash.h" +#include + #include @@ -98,7 +100,7 @@ static void intel_exitQuery(volatile uint8_t *base) } -void intel_register(void) +void ftmctrl_intel_register(void) { static const flash_ops_t ops = { .statusRead = intel_statusRead, @@ -126,6 +128,6 @@ void intel_register(void) }; for (size_t i = 0; i < sizeof(intel_devices) / sizeof(intel_devices[0]); i++) { - flash_register(&intel_devices[i]); + ftmctrl_flash_register(&intel_devices[i]); } } diff --git a/storage/flashdrv/drv/grlib-spimctrl/Makefile b/storage/flashdrv/drv/grlib-spimctrl/Makefile new file mode 100644 index 00000000..8f17025c --- /dev/null +++ b/storage/flashdrv/drv/grlib-spimctrl/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for Phoenix-RTOS libspimctrl driver +# +# Copyright 2025 Phoenix Systems +# + +NAME := libspimctrl +LOCAL_SRCS := flash.c flashdrv.c spimctrl.c +LOCAL_CFLAGS := -fvisibility=hidden + +include $(static-lib.mk) diff --git a/storage/flashdrv/drv/grlib-spimctrl/flash.c b/storage/flashdrv/drv/grlib-spimctrl/flash.c new file mode 100644 index 00000000..b714cfd7 --- /dev/null +++ b/storage/flashdrv/drv/grlib-spimctrl/flash.c @@ -0,0 +1,440 @@ +/* + * Phoenix-RTOS + * + * GRLIB SPIMCTRL Flash driver + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include +#include + +#include "flash.h" +#include "flashdrv.h" + + +#define FLASH_CMD_RDID 0x9fu + +/* Status register */ + +#define FLASH_SR_WIP 0x01u /* Write in progress */ +#define FLASH_SR_WEL 0x02u /* Write enable latch */ + +#define VID_MACRONIX 0xc2u +#define VID_SPANSION 0x01u + +/* clang-format off */ + +enum { write_disable = 0, write_enable }; + + +static const struct flash_cmds flash_spansionCmds = { + .rdsr = 0x05u, .wren = 0x06u, .wrdi = 0x04u, .rdear = 0x16u, + .wrear = 0x17u, .ce = 0x60u, .se = 0xd8u, .pp = 0x02u, .read = 0x03u +}; +/* clang-format on */ + + +static const struct flash_dev flash_devs[] = { + { "S25FL128S", VID_SPANSION, 0x2018u, &flash_spansionCmds } +}; + + +static struct { + void *base; +} common; + + +static int flash_readStatus(const struct flash_dev *dev, struct spimctrl *spimctrl, uint8_t *status) +{ + struct xferOp xfer; + const uint8_t cmd = dev->cmds->rdsr; + + xfer.type = xfer_opRead; + xfer.cmd = &cmd; + xfer.cmdLen = 1; + xfer.rxData = status; + xfer.dataLen = 1; + + return spimctrl_xfer(spimctrl, &xfer); +} + + +static int flash_waitBusy(const struct flash_dev *dev, struct spimctrl *spimctrl, time_t timeout) +{ + int res; + uint8_t status = 0; + time_t now, end; + (void)gettime(&end, NULL); + + end += timeout * 1000; + + do { + res = flash_readStatus(dev, spimctrl, &status); + if (res < 0) { + return res; + } + + (void)gettime(&now, NULL); + if ((timeout > 0) && (now > end)) { + return -ETIME; + } + } while ((status & FLASH_SR_WIP) != 0); + + return 0; +} + + +static int flash_writeEnable(const struct flash_dev *dev, struct spimctrl *spimctrl, int enable) +{ + int res; + struct xferOp xfer; + uint8_t status = 0; + const uint8_t cmd = (enable == 1) ? dev->cmds->wren : dev->cmds->wrdi; + + res = flash_waitBusy(dev, spimctrl, 0); + if (res < 0) { + return res; + } + + xfer.type = xfer_opWrite; + xfer.cmd = &cmd; + xfer.cmdLen = 1; + xfer.txData = NULL; + xfer.dataLen = 0; + + res = spimctrl_xfer(spimctrl, &xfer); + if (res < 0) { + return res; + } + + res = flash_readStatus(dev, spimctrl, &status); + if (res < 0) { + return res; + } + + status = (status & FLASH_SR_WEL) ? 1 : 0; + + if (status != enable) { + return -EIO; + } + + return 0; +} + + +static int flash_readEAR(const struct flash_dev *dev, struct spimctrl *spimctrl, uint8_t *status) +{ + struct xferOp xfer; + const uint8_t cmd = dev->cmds->rdear; + + xfer.type = xfer_opRead; + xfer.cmd = &cmd; + xfer.cmdLen = 1; + xfer.rxData = status; + xfer.dataLen = 1; + + return spimctrl_xfer(spimctrl, &xfer); +} + + +static int flash_writeEAR(const struct flash_dev *dev, struct spimctrl *spimctrl, uint8_t value) +{ + int res; + struct xferOp xfer; + const uint8_t cmd = dev->cmds->wrear; + + flash_writeEnable(dev, spimctrl, write_enable); + + xfer.type = xfer_opWrite; + xfer.cmd = &cmd; + xfer.cmdLen = 1; + xfer.txData = &value; + xfer.dataLen = 1; + + res = spimctrl_xfer(spimctrl, &xfer); + if (res < 0) { + return res; + } + + res = flash_readEAR(dev, spimctrl, &spimctrl->ear); + if (res < 0) { + return res; + } + + if (spimctrl->ear != value) { + return -EIO; + } + + return 0; +} + + +static int flash_validateEar(const struct flash_dev *dev, struct spimctrl *spimctrl, uint32_t addr) +{ + int res = 0; + const uint8_t desiredEar = (addr >> 24) & 0xffu; + + if (desiredEar != spimctrl->ear) { + res = flash_writeEAR(dev, spimctrl, desiredEar); + } + return res; +} + + +int spimctrl_flash_chipErase(const struct _storage_devCtx_t *ctx, time_t timeout) +{ + int res; + struct xferOp xfer; + const uint8_t cmd = ctx->dev->cmds->ce; + + res = flash_writeEnable(ctx->dev, ctx->spimctrl, write_enable); + if (res < 0) { + return res; + } + + xfer.type = xfer_opWrite; + xfer.cmd = &cmd; + xfer.cmdLen = 1; + xfer.txData = NULL; + xfer.dataLen = 0; + + res = spimctrl_xfer(ctx->spimctrl, &xfer); + if (res < 0) { + return res; + } + + return flash_waitBusy(ctx->dev, ctx->spimctrl, timeout); +} + + +int spimctrl_flash_sectorErase(const struct _storage_devCtx_t *ctx, addr_t addr, time_t timeout) +{ + int res = 0; + struct xferOp xfer; + uint8_t cmd[4] = { ctx->dev->cmds->se, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff }; + size_t regionEraseSz = 0, regionEnd = 0; + + for (size_t i = 0; i < ctx->cfi.regionCnt; i++) { + regionEnd += (ctx->cfi.regions[i].count + 1) * CFI_REGION_SIZE(ctx->cfi.regions[i].size); + if (addr < regionEnd) { + regionEraseSz = ctx->cfi.regions[i].size; + break; + } + } + + if (regionEraseSz == 0) { + return -EINVAL; + } + + for (size_t i = 0; i < ctx->sectorsz / regionEraseSz; i++) { + res = flash_validateEar(ctx->dev, ctx->spimctrl, addr); + if (res < 0) { + return res; + } + + res = flash_writeEnable(ctx->dev, ctx->spimctrl, write_enable); + if (res < 0) { + return res; + } + + xfer.type = xfer_opWrite; + xfer.cmd = cmd; + xfer.cmdLen = 4; + xfer.txData = NULL; + xfer.dataLen = 0; + + res = spimctrl_xfer(ctx->spimctrl, &xfer); + if (res < 0) { + return res; + } + + res = flash_waitBusy(ctx->dev, ctx->spimctrl, timeout); + if (res < 0) { + return res; + } + + addr += regionEraseSz; + cmd[1] = (addr >> 16) & 0xff; + cmd[2] = (addr >> 8) & 0xff; + cmd[3] = addr & 0xff; + } + + return 0; +} + + +int spimctrl_flash_pageProgram(const struct _storage_devCtx_t *ctx, addr_t addr, const void *src, size_t len, time_t timeout) +{ + struct xferOp xfer; + const uint8_t cmd[4] = { ctx->dev->cmds->pp, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff }; + + int res = flash_validateEar(ctx->dev, ctx->spimctrl, addr); + if (res < 0) { + return res; + } + + res = flash_writeEnable(ctx->dev, ctx->spimctrl, write_enable); + if (res < 0) { + return res; + } + + xfer.type = xfer_opWrite; + xfer.cmd = cmd; + xfer.cmdLen = 4; + xfer.txData = src; + xfer.dataLen = len; + + res = spimctrl_xfer(ctx->spimctrl, &xfer); + if (res < 0) { + return res; + } + + res = flash_waitBusy(ctx->dev, ctx->spimctrl, timeout); + + return res; +} + + +static ssize_t flash_readCmd(const struct flash_dev *dev, struct spimctrl *spimctrl, addr_t addr, void *data, size_t size) +{ + struct xferOp xfer; + const uint8_t cmd[4] = { dev->cmds->read, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff }; + + int res = flash_validateEar(dev, spimctrl, addr); + if (res < 0) { + return res; + } + + xfer.type = xfer_opRead; + xfer.cmd = cmd; + xfer.cmdLen = 4; + xfer.rxData = data; + xfer.dataLen = size; + + res = spimctrl_xfer(spimctrl, &xfer); + + return (res < 0) ? res : (ssize_t)size; +} + + +static ssize_t flash_readAhb(const struct flash_dev *dev, struct spimctrl *spimctrl, addr_t addr, void *data, size_t size) +{ + int res = flash_validateEar(dev, spimctrl, addr); + if (res < 0) { + return res; + } + + (void)memcpy(data, (void *)(addr + (uintptr_t)common.base), size); + + return (res < 0) ? res : (ssize_t)size; +} + + +ssize_t spimctrl_flash_readData(const struct _storage_devCtx_t *ctx, addr_t addr, void *data, size_t size) +{ + if (((addr & 0xff000000) == 0) && (((addr + size) & 0xff000000) != 0)) { + /* If we'd have to change EAR register during read, + * read data through command (can be read without EAR change) + */ + return flash_readCmd(ctx->dev, ctx->spimctrl, addr, data, size); + } + else { + /* Direct copy */ + return flash_readAhb(ctx->dev, ctx->spimctrl, addr, data, size); + } +} + + +static int flash_readId(const struct spimctrl *spimctrl, cfi_info_t *cfi) +{ + struct xferOp xfer; + const uint8_t cmd = FLASH_CMD_RDID; + + xfer.type = xfer_opRead; + xfer.cmd = &cmd; + xfer.cmdLen = 1; + xfer.rxData = (uint8_t *)cfi; + xfer.dataLen = sizeof(*cfi); + + return spimctrl_xfer(spimctrl, &xfer); +} + + +static uint16_t flash_deserialize16(uint16_t value) +{ + return ((value & 0xff) << 8) | ((value >> 8) & 0xff); +} + + +static const struct flash_dev *flash_query(struct spimctrl *spimctrl, cfi_info_t *cfi) +{ + if (flash_readId(spimctrl, cfi) < 0) { + return NULL; + } + + uint16_t device; + memcpy(&device, &cfi->vendorData[1], sizeof(device)); + device = flash_deserialize16(device); + + for (size_t i = 0; i < sizeof(flash_devs) / sizeof(flash_devs[0]); ++i) { + const struct flash_dev *flash = &flash_devs[i]; + if ((cfi->vendorData[0] == flash->vendor) && (device == flash->device)) { + + if (flash_readEAR(flash, spimctrl, &spimctrl->ear) < 0) { + return NULL; + } + + return flash; + } + } + + return NULL; +} + + +void spimctrl_flash_printInfo(const struct _storage_devCtx_t *ctx) +{ + LOG("configured %s %u MB flash", ctx->dev->name, CFI_SIZE(ctx->cfi.chipSz) / (1024 * 1024)); +} + + +int spimctrl_flash_init(struct _storage_devCtx_t *ctx, addr_t flashBase) +{ + ctx->dev = flash_query(ctx->spimctrl, &ctx->cfi); + + if (ctx->dev == NULL) { + return -1; + } + + ctx->sectorsz = 0; + + for (uint8_t reg = 0; reg < ctx->cfi.regionCnt; ++reg) { + if (ctx->sectorsz < CFI_REGION_SIZE(ctx->cfi.regions[reg].size)) { + ctx->sectorsz = CFI_REGION_SIZE(ctx->cfi.regions[reg].size); + } + } + + /* Map entire flash */ + common.base = mmap(NULL, CFI_SIZE(ctx->cfi.chipSz), PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, flashBase); + if (common.base == MAP_FAILED) { + LOG_ERROR("failed to map flash"); + return -ENOMEM; + } + + return 0; +} + + +void spimctrl_flash_destroy(struct _storage_devCtx_t *ctx) +{ + spimctrl_destroy(ctx->spimctrl); + (void)munmap(common.base, CFI_SIZE(ctx->cfi.chipSz)); +} diff --git a/storage/flashdrv/drv/grlib-spimctrl/flash.h b/storage/flashdrv/drv/grlib-spimctrl/flash.h new file mode 100644 index 00000000..98fb6582 --- /dev/null +++ b/storage/flashdrv/drv/grlib-spimctrl/flash.h @@ -0,0 +1,72 @@ +/* + * Phoenix-RTOS + * + * GRLIB SPIMCTRL Flash driver + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SPIMCTRL_FLASH_H_ +#define _SPIMCTRL_FLASH_H_ + + +#include + +#include + +#include "spimctrl.h" + +#define NOR_ERASED_STATE 0xffu +#define NOR_SECTORSZ_MAX 0x10000u +#define NOR_PAGESZ_MAX 0x100u + + +struct flash_cmds { + uint8_t rdsr; /* Read status register */ + uint8_t wren; /* Write enable */ + uint8_t wrdi; /* Write disable */ + uint8_t rdear; /* Read bank/extended address register */ + uint8_t wrear; /* Write bank/extended address register */ + uint8_t ce; /* Chip erase */ + uint8_t se; /* Sector erase */ + uint8_t pp; /* Page program */ + uint8_t read; +}; + + +struct flash_dev { + const char *name; + const uint8_t vendor; + const uint16_t device; + + const struct flash_cmds *cmds; +}; + + +int spimctrl_flash_chipErase(const struct _storage_devCtx_t *ctx, time_t timeout); + + +int spimctrl_flash_sectorErase(const struct _storage_devCtx_t *ctx, addr_t addr, time_t timeout); + + +int spimctrl_flash_pageProgram(const struct _storage_devCtx_t *ctx, addr_t addr, const void *src, size_t len, time_t timeout); + + +ssize_t spimctrl_flash_readData(const struct _storage_devCtx_t *ctx, addr_t addr, void *buff, size_t len); + + +void spimctrl_flash_printInfo(const struct _storage_devCtx_t *ctx); + + +int spimctrl_flash_init(struct _storage_devCtx_t *ctx, addr_t flashBase); + + +void spimctrl_flash_destroy(struct _storage_devCtx_t *ctx); + + +#endif /* _NOR_H_ */ diff --git a/storage/flashdrv/drv/grlib-spimctrl/flashdrv.c b/storage/flashdrv/drv/grlib-spimctrl/flashdrv.c new file mode 100644 index 00000000..cbd66816 --- /dev/null +++ b/storage/flashdrv/drv/grlib-spimctrl/flashdrv.c @@ -0,0 +1,376 @@ +/* + * Phoenix-RTOS + * + * GRLIB SPIMCTRL Flash driver + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "flashdrv.h" +#include "flash.h" + + +#define LIBCACHE_LINECNT 1024 +#define LIBCACHE_POLICY LIBCACHE_WRITE_BACK + + +/* MTD interface */ + + +static int _flashdrv_mtdRead(storage_t *strg, off_t offs, void *buff, size_t len, size_t *retlen) +{ + struct _storage_devCtx_t *ctx = strg->dev->ctx; + if (!common_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len)) { + *retlen = 0; + return -EINVAL; + } + + if (len == 0u) { + *retlen = 0; + return 0; + } + + ssize_t ret = spimctrl_flash_readData(ctx, offs, buff, len); + if (ret < 0) { + *retlen = 0; + return ret; + } + + *retlen = len; + + return 0; +} + + +static ssize_t _flashdrv_mtdReadCb(uint64_t offs, void *buff, size_t len, cache_devCtx_t *ctx) +{ + storage_t *strg = ctx->strg; + size_t retlen; + ssize_t ret; + + ret = _flashdrv_mtdRead(strg, offs, buff, len, &retlen); + if (ret < 0) { + return ret; + } + + return (ssize_t)retlen; +} + + +static int flashdrv_mtdRead(storage_t *strg, off_t offs, void *buff, size_t len, size_t *retlen) +{ + mutexLock(strg->dev->ctx->lock); + int ret = cache_read(strg->dev->ctx->cache, offs, buff, len); + mutexUnlock(strg->dev->ctx->lock); + + if (ret < 0) { + *retlen = 0; + } + else { + *retlen = len; + ret = 0; + } + + return ret; +} + + +static int _flashdrv_mtdWrite(storage_t *strg, off_t offs, const void *buff, size_t len, size_t *retlen) +{ + struct _storage_devCtx_t *ctx = strg->dev->ctx; + if (!common_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len)) { + *retlen = 0; + return -EINVAL; + } + + if (len == 0u) { + *retlen = 0; + return 0; + } + + const uint8_t *src = buff; + size_t doneBytes = 0; + + int res = 0; + const size_t pagesz = strg->dev->mtd->writeBuffsz; + + while (doneBytes < len) { + size_t chunk = min(pagesz - (offs % pagesz), len - doneBytes); + + res = spimctrl_flash_pageProgram(ctx, offs, src, chunk, + CFI_TIMEOUT_MAX_PROGRAM(ctx->cfi.toutTypical.bufWrite, ctx->cfi.toutMax.bufWrite)); + + if (res < 0) { + break; + } + + doneBytes += chunk; + src += chunk; + offs += chunk; + } + + *retlen = doneBytes; + + return res; +} + + +static ssize_t _flashdrv_mtdWriteCb(uint64_t offs, const void *buff, size_t len, cache_devCtx_t *ctx) +{ + storage_t *strg = ctx->strg; + size_t retlen; + ssize_t ret; + + if ((offs % strg->dev->mtd->writesz) != 0 || (len % strg->dev->mtd->writesz) != 0) { + return -EINVAL; + } + + ret = _flashdrv_mtdWrite(strg, offs, buff, len, &retlen); + if (ret < 0) { + return ret; + } + + return (ssize_t)retlen; +} + + +static int flashdrv_mtdWrite(storage_t *strg, off_t offs, const void *buff, size_t len, size_t *retlen) +{ + mutexLock(strg->dev->ctx->lock); + int ret = cache_write(strg->dev->ctx->cache, offs, buff, len, LIBCACHE_POLICY); + mutexUnlock(strg->dev->ctx->lock); + + if (ret < 0) { + *retlen = 0; + } + else { + *retlen = len; + ret = 0; + } + + return ret; +} + + +static int flashdrv_mtdErase(storage_t *strg, off_t offs, size_t len) +{ + if ((strg == NULL) || (strg->dev == NULL) || (strg->dev->ctx == NULL)) { + return -EINVAL; + } + + struct _storage_devCtx_t *ctx = strg->dev->ctx; + if (!common_isValidAddress(CFI_SIZE(ctx->cfi.chipSz), offs, len) || ((offs & (ctx->sectorsz - 1)) != 0) || (len % ctx->sectorsz != 0)) { + return -EINVAL; + } + + if (len == 0u) { + return 0; + } + + mutexLock(ctx->lock); + + off_t end; + int res = -ENOSYS; + if ((offs == 0) && (len == CFI_SIZE(ctx->cfi.chipSz))) { + TRACE("erasing entire memory"); + res = spimctrl_flash_chipErase(ctx, CFI_TIMEOUT_MAX_ERASE(ctx->cfi.toutTypical.chipErase, ctx->cfi.toutMax.chipErase)); + end = CFI_SIZE(ctx->cfi.chipSz); + } + else { + end = common_getSectorOffset(ctx->sectorsz, offs + len + ctx->sectorsz - 1u); + TRACE("erasing sectors from 0x%jx to 0x%jx", (uintmax_t)offs, (uintmax_t)end); + } + + if (res == -ENOSYS) { + off_t secOffs = offs; + while (secOffs < end) { + res = spimctrl_flash_sectorErase(ctx, secOffs, CFI_TIMEOUT_MAX_ERASE(ctx->cfi.toutTypical.blkErase, ctx->cfi.toutMax.blkErase)); + if (res < 0) { + break; + } + secOffs += ctx->sectorsz; + } + } + + res = cache_invalidate(ctx->cache, offs, end); + mutexUnlock(ctx->lock); + + return res; +} + + +static const storage_mtdops_t mtdOps = { + .erase = flashdrv_mtdErase, + .unPoint = NULL, + .point = NULL, + .read = flashdrv_mtdRead, + .write = flashdrv_mtdWrite, + + .meta_read = NULL, + .meta_write = NULL, + + .sync = NULL, + .lock = NULL, + .unLock = NULL, + .isLocked = NULL, + + .block_isBad = NULL, + .block_isReserved = NULL, + .block_markBad = NULL, + .block_maxBadNb = NULL, + + .suspend = NULL, + .resume = NULL, + .reboot = NULL, +}; + + +static void flashdrv_destroy(storage_t *strg) +{ + if (strg == NULL) { + return; + } + + if (strg->dev != NULL) { + if (strg->dev->ctx != NULL) { + if (strg->dev->ctx->cache != NULL) { + cache_deinit(strg->dev->ctx->cache); + } + (void)resourceDestroy(strg->dev->ctx->lock); + spimctrl_flash_destroy(strg->dev->ctx); + free(strg->dev->ctx->spimctrl); + } + free(strg->dev->ctx); + free(strg->dev->mtd); + free(strg->dev); + } + free(strg); + strg = NULL; +} + + +static storage_t *flashdrv_init(addr_t mctrlBase, addr_t flashBase) +{ + struct _storage_devCtx_t *ctx = calloc(1, sizeof(struct _storage_devCtx_t)); + if (ctx == NULL) { + LOG_ERROR(); + return NULL; + } + + ctx->spimctrl = calloc(1, sizeof(struct spimctrl)); + if (ctx->spimctrl == NULL) { + free(ctx); + return NULL; + } + + if (spimctrl_init(ctx->spimctrl, mctrlBase) < 0) { + free(ctx->spimctrl); + free(ctx); + return NULL; + } + + if (spimctrl_flash_init(ctx, flashBase) < 0) { + free(ctx->spimctrl); + free(ctx); + return NULL; + } + + if (mutexCreate(&ctx->lock) < 0) { + spimctrl_flash_destroy(ctx); + free(ctx->spimctrl); + free(ctx); + return NULL; + } + + storage_t *strg = calloc(1, sizeof(storage_t)); + if (strg == NULL) { + spimctrl_flash_destroy(ctx); + free(ctx->spimctrl); + free(ctx); + return NULL; + } + + strg->start = 0; + strg->size = CFI_SIZE(ctx->cfi.chipSz); + + strg->dev = calloc(1, sizeof(storage_dev_t)); + if (strg->dev == NULL) { + spimctrl_flash_destroy(ctx); + free(ctx->spimctrl); + free(ctx); + free(strg); + return NULL; + } + + /* Assign device context */ + strg->dev->ctx = ctx; + + storage_mtd_t *mtd = calloc(1, sizeof(storage_mtd_t)); + if (mtd == NULL) { + flashdrv_destroy(strg); + return NULL; + } + + /* MTD interface */ + mtd->ops = &mtdOps; + mtd->type = mtd_norFlash; + mtd->name = ctx->dev->name; + mtd->metaSize = 0; + mtd->oobSize = 0; + mtd->oobAvail = 0; + + mtd->writeBuffsz = CFI_SIZE(ctx->cfi.bufSz); + mtd->writesz = 1; + mtd->erasesz = ctx->sectorsz; + + strg->dev->mtd = mtd; + + /* No block device interface */ + strg->dev->blk = NULL; + + /* Initialize cache */ + cache_ops_t cacheOps = { + .readCb = _flashdrv_mtdReadCb, + .writeCb = _flashdrv_mtdWriteCb, + .ctx = &strg->dev->ctx->cacheCtx + }; + strg->dev->ctx->cache = cache_init(strg->size, strg->dev->mtd->writeBuffsz, LIBCACHE_LINECNT, &cacheOps); + if (strg->dev->ctx->cache == NULL) { + flashdrv_destroy(strg); + return NULL; + } + strg->dev->ctx->cacheCtx.strg = strg; + + spimctrl_flash_printInfo(ctx); + + return strg; +} + + +void __attribute__((constructor)) spimctrl_register(void) +{ + static const struct flash_driver spimctrl = { + .name = "spimctrl", + .init = flashdrv_init, + .destroy = flashdrv_destroy, + }; + + flashsrv_register(&spimctrl); +} diff --git a/storage/flashdrv/drv/grlib-spimctrl/flashdrv.h b/storage/flashdrv/drv/grlib-spimctrl/flashdrv.h new file mode 100644 index 00000000..c830a709 --- /dev/null +++ b/storage/flashdrv/drv/grlib-spimctrl/flashdrv.h @@ -0,0 +1,44 @@ +/* + * Phoenix-RTOS + * + * GRLIB SPIMCTRL Flash driver + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#ifndef _SPIMCTRL_FLASHDRV_H_ +#define _SPIMCTRL_FLASHDRV_H_ + + +#include +#include +#include +#include + + +struct cache_devCtx_s { + struct _storage_t *strg; +}; + + +struct _storage_devCtx_t { + cfi_info_t cfi; + const struct flash_dev *dev; + + struct spimctrl *spimctrl; + + handle_t lock; + size_t sectorsz; + + cachectx_t *cache; + cache_devCtx_t cacheCtx; +}; + + +#endif diff --git a/storage/flashdrv/drv/grlib-spimctrl/spimctrl.c b/storage/flashdrv/drv/grlib-spimctrl/spimctrl.c new file mode 100644 index 00000000..6ef25305 --- /dev/null +++ b/storage/flashdrv/drv/grlib-spimctrl/spimctrl.c @@ -0,0 +1,161 @@ +/* + * Phoenix-RTOS + * + * GRLIB SPIMCTRL driver + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include + +#include + +#include "spimctrl.h" + +/* Control register */ + +#define USR_CTRL (1 << 0) +#define CHIP_SEL (1 << 3) +#define CORE_RST (1 << 4) + +/* Status register */ + +#define OPER_DONE (1 << 0) +#define CORE_BUSY (1 << 1) +#define INITIALIZED (1 << 2) + + +enum { + flash_cfg, /* Flash configuration : 0x00 */ + flash_ctrl, /* Flash control : 0x04 */ + flash_stat, /* Flash status : 0x08 */ + flash_rx, /* Flash receive : 0x0C */ + flash_tx, /* Flash transmit : 0x10 */ + flash_econf, /* EDAC configuration : 0x14 */ + flash_estat /* EDAC status : 0x18 */ +}; + + +static void spimctrl_userCtrl(volatile uint32_t *spimctrlBase) +{ + *(spimctrlBase + flash_ctrl) = USR_CTRL; + *(spimctrlBase + flash_ctrl) &= ~CHIP_SEL; +} + + +static int spimctrl_busy(const struct spimctrl *spimctrl) +{ + return (*(spimctrl->base + flash_stat) & CORE_BUSY) >> 1; +} + + +static int spimctrl_ready(const struct spimctrl *spimctrl) +{ + uint32_t val = (*(spimctrl->base + flash_stat) & (INITIALIZED | OPER_DONE)); + + return (val == INITIALIZED) ? 1 : 0; +} + + +static void spimctrl_tx(volatile uint32_t *spimctrlBase, uint8_t cmd) +{ + *(spimctrlBase + flash_tx) = cmd; + while ((*(spimctrlBase + flash_stat) & OPER_DONE) == 0) { } + *(spimctrlBase + flash_stat) |= OPER_DONE; +} + + +static uint8_t spimctrl_rx(volatile uint32_t *spimctrlBase) +{ + return *(spimctrlBase + flash_rx) & 0xff; +} + + +static void spimctrl_read(const struct spimctrl *spimctrl, struct xferOp *op) +{ + spimctrl_userCtrl(spimctrl->base); + + /* send command */ + for (size_t i = 0; i < op->cmdLen; i++) { + spimctrl_tx(spimctrl->base, op->cmd[i]); + } + + /* read data */ + for (size_t i = 0; i < op->dataLen; i++) { + spimctrl_tx(spimctrl->base, 0x00u); + op->rxData[i] = spimctrl_rx(spimctrl->base); + } + + *(spimctrl->base + flash_ctrl) &= ~USR_CTRL; +} + + +static void spimctrl_write(const struct spimctrl *spimctrl, struct xferOp *op) +{ + spimctrl_userCtrl(spimctrl->base); + + /* Send command */ + for (size_t i = 0; i < op->cmdLen; i++) { + spimctrl_tx(spimctrl->base, op->cmd[i]); + } + + /* Send data */ + for (size_t i = 0; i < op->dataLen; i++) { + spimctrl_tx(spimctrl->base, op->txData[i]); + } + + *(spimctrl->base + flash_ctrl) &= ~USR_CTRL; +} + + +int spimctrl_xfer(const struct spimctrl *spimctrl, struct xferOp *op) +{ + if ((spimctrl_busy(spimctrl) == 1) || spimctrl_ready(spimctrl) == 0) { + return -EBUSY; + } + + switch (op->type) { + case xfer_opRead: + spimctrl_read(spimctrl, op); + break; + case xfer_opWrite: + spimctrl_write(spimctrl, op); + break; + default: + return -EINVAL; + } + return 0; +} + + +void spimctrl_reset(const struct spimctrl *spimctrl) +{ + *(spimctrl->base + flash_ctrl) = CORE_RST; +} + + +int spimctrl_init(struct spimctrl *spimctrl, addr_t mctrlBase) +{ + spimctrl->base = mmap(NULL, _PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_DEVICE | MAP_PHYSMEM | MAP_ANONYMOUS, -1, mctrlBase); + if (spimctrl->base == MAP_FAILED) { + return -ENOMEM; + } + + /* Reset core */ + spimctrl_reset(spimctrl); + + return 0; +} + + +void spimctrl_destroy(struct spimctrl *spimctrl) +{ + (void)munmap((void *)spimctrl->base, _PAGE_SIZE); +} diff --git a/storage/flashdrv/drv/grlib-spimctrl/spimctrl.h b/storage/flashdrv/drv/grlib-spimctrl/spimctrl.h new file mode 100644 index 00000000..db75d668 --- /dev/null +++ b/storage/flashdrv/drv/grlib-spimctrl/spimctrl.h @@ -0,0 +1,57 @@ +/* + * Phoenix-RTOS + * + * GRLIB SPIMCTRL driver + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _SPIMCTRL_H_ +#define _SPIMCTRL_H_ + +#include +#include + + +struct spimctrl { + volatile uint32_t *base; + + uint8_t ear; +}; + + +struct xferOp { + /* clang-format off */ + enum { xfer_opRead = 0, xfer_opWrite } type; + /* clang-format on */ + const uint8_t *cmd; + size_t cmdLen; + union { + const uint8_t *txData; + uint8_t *rxData; + }; + size_t dataLen; +}; + + +/* Execute a transfer through spimctrl */ +int spimctrl_xfer(const struct spimctrl *spimctrl, struct xferOp *op); + + +/* Reset spimctrl core */ +void spimctrl_reset(const struct spimctrl *spimctrl); + + +/* Initialize spimctrl instance */ +int spimctrl_init(struct spimctrl *spimctrl, addr_t mctrlBase); + + +void spimctrl_destroy(struct spimctrl *spimctrl); + + +#endif diff --git a/storage/ftmctrl-flash/flashsrv.c b/storage/flashdrv/flashsrv.c similarity index 68% rename from storage/ftmctrl-flash/flashsrv.c rename to storage/flashdrv/flashsrv.c index e214a641..c3b9c57f 100644 --- a/storage/ftmctrl-flash/flashsrv.c +++ b/storage/flashdrv/flashsrv.c @@ -5,7 +5,7 @@ * * Flash server * - * Copyright 2023 Phoenix Systems + * Copyright 2023-2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -30,12 +30,29 @@ #include #include -#include "flashdrv.h" -#include "flash.h" -#include "ftmctrl.h" +#include #define STRG_PATH "mtd0" +#define MAX_DRIVERS 4 + + +struct flashsrv_opts { + const struct flash_driver *driver; + addr_t mctrlBase; + addr_t flashBase; + struct { + char *partname; + char *fs; + } root; +}; + + +static struct { + const struct flash_driver *registry[MAX_DRIVERS]; + size_t ndrivers; +} common; + /* Flash server operations */ @@ -97,7 +114,7 @@ static int flashsrv_sync(storage_t *strg) storage_mtd_t *mtd = strg->dev->mtd; if ((mtd != NULL) && (mtd->ops != NULL) && (mtd->ops->sync != NULL)) { mtd->ops->sync(strg); - return EOK; + return 0; } return -EINVAL; @@ -119,7 +136,7 @@ static int flashsrv_getAttr(storage_t *strg, int type, long long *attr) return -EINVAL; } - return EOK; + return 0; } @@ -135,46 +152,46 @@ static void flashsrv_msgHandler(void *arg, msg_t *msg) case mtOpen: case mtClose: strg = storage_get(msg->oid.id); - msg->o.err = (strg == NULL) ? -EINVAL : EOK; + msg->o.err = (strg == NULL) ? -EINVAL : 0; TRACE("mtOpen/mtClose: %d", msg->o.err); break; case mtRead: strg = storage_get(msg->oid.id); - TRACE("mtRead: id: %u, size: %d, off: %llu", msg->oid.id, msg->o.size, msg->i.io.offs); + TRACE("mtRead: id: %ju, size: %zu, off: %ju", (uintmax_t)msg->oid.id, msg->o.size, (uintmax_t)msg->i.io.offs); msg->o.err = flashsrv_read(strg, msg->i.io.offs, msg->o.data, msg->o.size); break; case mtWrite: strg = storage_get(msg->oid.id); - TRACE("mtWrite: id: %u, size: %d, off: %llu", msg->oid.id, msg->o.size, msg->i.io.offs); + TRACE("mtWrite: id: %ju, size: %zu, off: %ju", (uintmax_t)msg->oid.id, msg->o.size, (uintmax_t)msg->i.io.offs); msg->o.err = flashsrv_write(strg, msg->i.io.offs, msg->o.data, msg->o.size); break; case mtSync: strg = storage_get(msg->oid.id); - TRACE("mtSync: id: %u", msg->oid.id); + TRACE("mtSync: id: %ju", (uintmax_t)msg->oid.id); msg->o.err = flashsrv_sync(strg); break; case mtGetAttr: strg = storage_get(msg->oid.id); - TRACE("mtGetAttr: id: %u, type: %d", msg->oid.id, msg->i.attr.type); + TRACE("mtGetAttr: id: %ju, type: %d", (uintmax_t)msg->oid.id, msg->i.attr.type); msg->o.err = flashsrv_getAttr(strg, msg->i.attr.type, &msg->o.attr.val); break; case mtMount: - TRACE("mtMount: id: %u, fstype: %s, mode: %ld", msg->oid.id, imnt->fstype, imnt->mode); + TRACE("mtMount: id: %ju, fstype: %s, mode: %ld", (uintmax_t)msg->oid.id, imnt->fstype, imnt->mode); msg->o.err = storage_mountfs(storage_get(msg->oid.id), imnt->fstype, msg->i.data, imnt->mode, &imnt->mnt, &omnt->oid); break; case mtUmount: - TRACE("mtUmount: id: %u", msg->oid.id); + TRACE("mtUmount: id: %ju", (uintmax_t)msg->oid.id); msg->o.err = storage_umountfs(storage_get(msg->oid.id)); break; case mtMountPoint: - TRACE("mtMountPoint: id: %u", msg->oid.id); + TRACE("mtMountPoint: id: %ju", (uintmax_t)msg->oid.id); msg->o.err = storage_mountpoint(storage_get(msg->oid.id), &omnt->oid); break; @@ -217,7 +234,7 @@ static int flashsrv_mountRoot(const char *name, const char *fstype) return res; } - return EOK; + return 0; } @@ -227,111 +244,104 @@ static void flashsrv_help(const char *prog) printf("\t-r - mount partition as root\n"); printf("\t use psdisk to create partitions\n"); printf("\t-h - print this message\n"); + printf("\t-c - use as memory controller base address (required)\n"); + printf("\t-m - use as flash memory base address (required)\n"); + printf("\t-d - use for flash memory (required)\n"); + printf("\t available drivers: \n"); + printf("\t "); + + for (size_t i = 0; i < common.ndrivers; i++) { + printf("%s%s", common.registry[i]->name, (i < common.ndrivers - 1) ? ", " : "\n"); + } } -static int flashsrv_parseArgs(int argc, char **argv) +static int flashsrv_parseInitArgs(int argc, char **argv, struct flashsrv_opts *opts) { for (;;) { - int c = getopt(argc, argv, "r:h"); + int c = getopt(argc, argv, "r:d:c:m:h"); if (c == -1) { return 0; } - char *partName, *fs; switch (c) { - case 'r': - partName = optarg; - fs = strchr(optarg, ':'); - if (fs == NULL) { + case 'h': + flashsrv_help(argv[0]); + return -1; + + case 'd': { + const char *name = optarg; + for (size_t i = 0; i < common.ndrivers; i++) { + if (strcmp(common.registry[i]->name, name) == 0) { + opts->driver = common.registry[i]; + break; + } + } + if (opts->driver == NULL) { + LOG_ERROR("Unknown driver: %s", name); + return -1; + } + break; + } + + case 'r': { + opts->root.partname = optarg; + opts->root.fs = strchr(optarg, ':'); + if (opts->root.fs == NULL) { LOG_ERROR("Invalid argument: %s", optarg); return -1; } - *fs = '\0'; - fs++; - if (flashsrv_mountRoot(partName, fs) < 0) { - LOG_ERROR("Failed to mount root filesystem"); + *opts->root.fs = '\0'; + opts->root.fs++; + break; + } + + case 'c': + errno = 0; + opts->mctrlBase = strtoul(optarg, NULL, 0); + if ((opts->mctrlBase == 0) && (errno != 0)) { + LOG_ERROR("Invalid argument: %s", optarg); return -1; } break; - case 'h': - flashsrv_help(argv[0]); - return -1; + case 'm': + errno = 0; + opts->flashBase = strtoul(optarg, NULL, 0); + if ((opts->flashBase == 0) && (errno != 0)) { + LOG_ERROR("Invalid argument: %s", optarg); + return -1; + } + break; default: LOG_ERROR("Unknown option: %c", c); return -1; } } + + return 0; } /* Initialization functions */ -static int flashsrv_devInit(storage_t *strg, struct _storage_devCtx_t *ctx) +void flashsrv_register(const struct flash_driver *driver) { - if (strg->parent == NULL) { - strg->start = 0; - strg->size = CFI_SIZE(ctx->cfi.chipSz); + if (common.ndrivers < MAX_DRIVERS) { + common.registry[common.ndrivers++] = driver; } - - /* Initialize device structure */ - strg->dev = malloc(sizeof(storage_dev_t)); - if (strg->dev == NULL) { - return -ENOMEM; - } - - /* Initialize MTD interface */ - storage_mtd_t *mtd = malloc(sizeof(storage_mtd_t)); - if (mtd == NULL) { - free(strg->dev); - return -ENOMEM; - } - - mtd->ops = flashdrv_getMtdOps(); - mtd->type = mtd_norFlash; - mtd->name = ctx->dev->name; - mtd->metaSize = 0; - mtd->oobSize = 0; - mtd->oobAvail = 0; - - uint8_t shift = ((ctx->dev->chipWidth == 16) && (ftmctrl_portWidth(ctx->ftmctrl) == 8)) ? 1 : 0; - mtd->writeBuffsz = CFI_SIZE(ctx->cfi.bufSz) >> shift; - mtd->writesz = 1; - mtd->erasesz = ctx->sectorsz; - - strg->dev->mtd = mtd; - - /* No block device interface */ - strg->dev->blk = NULL; - - /* Assign device context */ - strg->dev->ctx = ctx; - - return EOK; -} - - -static void flashsrv_devDestroy(storage_t *strg) -{ - if (strg->dev != NULL) { - if (strg->dev->mtd != NULL) { - free(strg->dev->mtd); - } - if (strg->dev->blk != NULL) { - free(strg->dev->blk); - } - free(strg->dev); - strg->dev = NULL; + else { + LOG("Too many drivers: %s not registered. Please increase MAX_DRIVERS", driver->name); } } static ptable_t *flashsrv_ptableRead(storage_t *strg) { - uint32_t count, offs = CFI_SIZE(strg->dev->ctx->cfi.chipSz) - strg->dev->ctx->sectorsz; + uint32_t count; + off_t offs = strg->size - strg->dev->mtd->erasesz; /* Read number of partitions */ if (flashsrv_read(strg, offs, &count, sizeof(count)) != sizeof(count)) { return NULL; @@ -340,7 +350,7 @@ static ptable_t *flashsrv_ptableRead(storage_t *strg) /* Verify ptable size */ uint32_t size = ptable_size(count); - if (size > strg->dev->ctx->sectorsz) { + if (size > strg->dev->mtd->erasesz) { return NULL; } @@ -365,7 +375,7 @@ static ptable_t *flashsrv_ptableRead(storage_t *strg) return NULL; } - if (ptable_deserialize(ptable, CFI_SIZE(strg->dev->ctx->cfi.chipSz), strg->dev->ctx->sectorsz) < 0) { + if (ptable_deserialize(ptable, strg->size, strg->dev->mtd->erasesz) < 0) { free(ptable); return NULL; } @@ -398,7 +408,6 @@ static int flashsrv_partAdd(storage_t *parent, uint32_t offset, uint32_t size, c int res = storage_add(part, &oid); if (res < 0) { LOG_ERROR("failed to add a partition"); - flashsrv_devDestroy(part); free(part); return res; } @@ -407,7 +416,6 @@ static int flashsrv_partAdd(storage_t *parent, uint32_t offset, uint32_t size, c if (snprintf(path, sizeof(path), "%s.%s", STRG_PATH, name) >= sizeof(path)) { LOG_ERROR("failed to build partition path"); storage_remove(part); - flashsrv_devDestroy(part); free(part); return -ENAMETOOLONG; } @@ -416,14 +424,13 @@ static int flashsrv_partAdd(storage_t *parent, uint32_t offset, uint32_t size, c if (res < 0) { LOG_ERROR("failed to create partition device file"); storage_remove(part); - flashsrv_devDestroy(part); free(part); return res; } TRACE("initialized partition %s: offset=%u, size=%u", name, offset, size); - return EOK; + return 0; } @@ -449,44 +456,19 @@ static int flashsrv_partsInit(storage_t *strg) } -static storage_t *flashsrv_init(void) +static storage_t *flashsrv_init(struct flashsrv_opts *opts) { - storage_t *strg = calloc(1, sizeof(storage_t)); + storage_t *strg = opts->driver->init(opts->mctrlBase, opts->flashBase); if (strg == NULL) { - LOG_ERROR("failed to allocate storage_t"); - return NULL; - } - - struct _storage_devCtx_t *ctx = flashdrv_contextInit(); - if (ctx == NULL) { - LOG_ERROR("failed to initialize flash context"); - free(strg); - return NULL; - } - - int res = flashsrv_devInit(strg, ctx); - if (res < 0) { - LOG_ERROR("failed to initialize libstorage interface (%d)", res); - flashdrv_contextDestroy(ctx); - free(strg); - return NULL; - } - - if (flashdrv_cacheInit(strg) < 0) { - free(strg->dev->mtd); - free(strg->dev); - flashdrv_contextDestroy(ctx); - free(strg); + LOG_ERROR("failed initialize storage interface"); return NULL; } oid_t oid; - res = storage_add(strg, &oid); + int res = storage_add(strg, &oid); if (res < 0) { LOG_ERROR("failed to add storage device (%d)", res); - flashdrv_contextDestroy(ctx); - flashsrv_devDestroy(strg); - free(strg); + opts->driver->destroy(strg); return NULL; } @@ -494,9 +476,7 @@ static storage_t *flashsrv_init(void) if (res < 0) { LOG_ERROR("failed to create device file (%d)", res); storage_remove(strg); - flashdrv_contextDestroy(ctx); - flashsrv_devDestroy(strg); - free(strg); + opts->driver->destroy(strg); return NULL; } @@ -536,8 +516,26 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + struct flashsrv_opts opts = { + .driver = NULL, + .mctrlBase = (addr_t)-1, + .flashBase = (addr_t)-1, + .root = { 0 } + }; + + int err = flashsrv_parseInitArgs(argc, argv, &opts); + if (err < 0) { + exit(EXIT_FAILURE); + } + + if ((opts.driver == NULL) || (opts.mctrlBase == (addr_t)-1) || (opts.flashBase == (addr_t)-1)) { + LOG("Required arguments not present"); + flashsrv_help(argv[0]); + exit(EXIT_FAILURE); + } + /* Initialize storage library with the message handler for the flash memory */ - int err = storage_init(flashsrv_msgHandler, 16); + err = storage_init(flashsrv_msgHandler, 16); if (err < 0) { LOG_ERROR("failed to initialize server (%d)\n", err); exit(EXIT_FAILURE); @@ -551,7 +549,7 @@ int main(int argc, char **argv) } /* Initialize flash driver and mtd interface */ - storage_t *strg = flashsrv_init(); + storage_t *strg = flashsrv_init(&opts); if (strg == NULL) { exit(EXIT_FAILURE); } @@ -559,23 +557,28 @@ int main(int argc, char **argv) /* Read partition table and initialize */ if (flashsrv_partsInit(strg) < 0) { storage_remove(strg); - flashdrv_contextDestroy(strg->dev->ctx); - flashsrv_devDestroy(strg); - free(strg); + opts.driver->destroy(strg); exit(EXIT_FAILURE); } - if (flashsrv_parseArgs(argc, argv) < 0) { - storage_remove(strg); - flashdrv_contextDestroy(strg->dev->ctx); - flashsrv_devDestroy(strg); - free(strg); - exit(EXIT_FAILURE); + if ((opts.root.partname != NULL) && (opts.root.fs != NULL)) { + if (flashsrv_mountRoot(opts.root.partname, opts.root.fs) < 0) { + storage_remove(strg); + opts.driver->destroy(strg); + exit(EXIT_FAILURE); + } } /* Finished server initialization - kill parent */ kill(getppid(), SIGUSR1); - storage_run(1, 2 * _PAGE_SIZE); + err = storage_run(1, 2 * _PAGE_SIZE); + + storage_remove(strg); + opts.driver->destroy(strg); + + if (err < 0) { + exit(EXIT_FAILURE); + } return EXIT_SUCCESS; } diff --git a/storage/ftmctrl-flash/cfi.h b/storage/flashdrv/include/flashdrv/cfi.h similarity index 69% rename from storage/ftmctrl-flash/cfi.h rename to storage/flashdrv/include/flashdrv/cfi.h index 36bd03a2..6e67b7da 100644 --- a/storage/ftmctrl-flash/cfi.h +++ b/storage/flashdrv/include/flashdrv/cfi.h @@ -5,7 +5,7 @@ * * CFI * - * Copyright 2024 Phoenix Systems + * Copyright 2025 Phoenix Systems * Author: Lukasz Leczkowski * * This file is part of Phoenix-RTOS. @@ -13,17 +13,18 @@ * %LICENSE% */ -#ifndef _CFI_H_ -#define _CFI_H_ +#ifndef _FLASHDRV_CFI_H_ +#define _FLASHDRV_CFI_H_ #include /* Timeouts in us */ -#define CFI_TIMEOUT_MAX_PROGRAM(typical, maximum) ((1u << typical) * (1u << maximum) * 2) -#define CFI_TIMEOUT_MAX_ERASE(typical, maximum) ((1u << typical) * (1u << maximum) * 1024u * 2) +#define CFI_TIMEOUT_MAX_PROGRAM(typical, maximum) ((1u << (typical)) * (1u << (maximum))) +#define CFI_TIMEOUT_MAX_ERASE(typical, maximum) ((1u << (typical)) * (1u << (maximum)) * 1024u) -#define CFI_SIZE(size) (1u << ((uint32_t)size)) +#define CFI_SIZE(size) (1u << ((uint32_t)(size))) +#define CFI_REGION_SIZE(size) ((size) * 256u) typedef struct { diff --git a/storage/flashdrv/include/flashdrv/common.h b/storage/flashdrv/include/flashdrv/common.h new file mode 100644 index 00000000..00cb4e2b --- /dev/null +++ b/storage/flashdrv/include/flashdrv/common.h @@ -0,0 +1,30 @@ +/* + * Phoenix-RTOS + * + * GRLIB FTMCTRL Flash driver + * + * Common auxiliary functions + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _FLASHDRV_COMMON_H_ +#define _FLASHDRV_COMMON_H_ + + +#include +#include + + +off_t common_getSectorOffset(size_t sectorsz, off_t offs); + + +bool common_isValidAddress(size_t memsz, off_t offs, size_t len); + + +#endif diff --git a/storage/flashdrv/include/flashdrv/flash_interface.h b/storage/flashdrv/include/flashdrv/flash_interface.h new file mode 100644 index 00000000..bb424d46 --- /dev/null +++ b/storage/flashdrv/include/flashdrv/flash_interface.h @@ -0,0 +1,28 @@ +/* + * Phoenix-RTOS + * + * Flash driver interface + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _FLASHDRV_FLASH_INTERFACE_H_ +#define _FLASHDRV_FLASH_INTERFACE_H_ + + +#include + + +struct flash_driver { + const char *name; + storage_t *(*init)(addr_t mctrlBase, addr_t flashBase); + void (*destroy)(storage_t *strg); +}; + + +#endif diff --git a/storage/flashdrv/include/flashdrv/flashsrv.h b/storage/flashdrv/include/flashdrv/flashsrv.h new file mode 100644 index 00000000..4f709c41 --- /dev/null +++ b/storage/flashdrv/include/flashdrv/flashsrv.h @@ -0,0 +1,30 @@ +/* + * Phoenix-RTOS + * + * Flash server + * + * Copyright 2025 Phoenix Systems + * Author: Lukasz Leczkowski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _FLASHDRV_FLASHSRV_H_ +#define _FLASHDRV_FLASHSRV_H_ + +#include +#include + +/* clang-format off */ +#define LOG(fmt, ...) do { (void)fprintf(stdout, "flashsrv: " fmt "\n", ##__VA_ARGS__); } while (0) +#define LOG_ERROR(fmt, ...) do { (void)fprintf(stdout, "flashsrv:%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); } while (0) +#define TRACE(fmt, ...) do { if (0) { (void)fprintf(stdout, "flashsrv:%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); } } while (0) +/* clang-format on */ + + +void flashsrv_register(const struct flash_driver *driver); + + +#endif diff --git a/storage/ftmctrl-flash/Makefile b/storage/ftmctrl-flash/Makefile deleted file mode 100644 index b62ae3fb..00000000 --- a/storage/ftmctrl-flash/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# -# Makefile for Phoenix-RTOS ftmctrl-flash driver -# -# Copyright 2023, 2024 Phoenix Systems -# - -NAME := libflashdrv-ftmctrl -LOCAL_SRCS := amd-flash.c flashdrv.c flash.c intel-flash.c - -include $(static-lib.mk) - -NAME := ftmctrl-flash -LOCAL_SRCS := flashsrv.c -DEP_LIBS := libflashdrv-ftmctrl -LIBS := libjffs2 libstorage libmtd libptable libcache - -include $(binary.mk) diff --git a/storage/ftmctrl-flash/flashdrv.h b/storage/ftmctrl-flash/flashdrv.h deleted file mode 100644 index 1c2dd49c..00000000 --- a/storage/ftmctrl-flash/flashdrv.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Phoenix-RTOS - * - * GRLIB FTMCTRL Flash driver - * - * Copyright 2023 Phoenix Systems - * Author: Lukasz Leczkowski - * - * This file is part of Phoenix-RTOS. - * - * %LICENSE% - */ - -#ifndef _FLASHDRV_H_ -#define _FLASHDRV_H_ - -#include "cfi.h" - -#include -#include -#include -#include - -/* clang-format off */ -#define LOG(fmt, ...) do { (void)fprintf(stdout, "ftmctrl-flashsrv: " fmt "\n", ##__VA_ARGS__); } while (0) -#define LOG_ERROR(fmt, ...) do { (void)fprintf(stdout, "ftmctrl-flashsrv:%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); } while (0) -#define TRACE(fmt, ...) do { if (0) { (void)fprintf(stdout, "ftmctrl-flashsrv:%s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__); } } while (0) -/* clang-format on */ - - -struct cache_devCtx_s { - struct _storage_t *strg; -}; - - -struct _storage_devCtx_t { - cfi_info_t cfi; - const struct _flash_dev_t *dev; - - handle_t lock; - void *ftmctrl; - size_t sectorsz; - - cachectx_t *cache; - cache_devCtx_t cacheCtx; -}; - - -const storage_mtdops_t *flashdrv_getMtdOps(void); - - -struct _storage_devCtx_t *flashdrv_contextInit(void); - - -int flashdrv_cacheInit(storage_t *strg); - - -void flashdrv_contextDestroy(struct _storage_devCtx_t *ctx); - - -#endif