Драйвер devf-spi-s25 для ЗОСРВ Нейтрино редакции 2020

This commit is contained in:
commit 8105ec52ab
29 changed files with 1279 additions and 0 deletions

2
Makefile Normal file
View File

@ -0,0 +1,2 @@
LIST=hardware
include recurse.mk

53
README.md Normal file
View File

@ -0,0 +1,53 @@
## Общая структура
```
┌───────────────────────────┐
│ │
│ SPI flash │
│ │
└─────────────▴─────────────┘
┌─────────────┴─────────────┐
│ │
│ Драйвер носителя (devf-*) │
│ │
└─────────────▴─────────────┘
┌─────────────┴─────────────┐
│ │
│ Клиентское приложение │
│ │
└───────────────────────────┘
```
## Дерево исходных кодов
```
|- flash/
| |- spi-s25/ - Исходный код flash-драйвера для устройств на базе 1890ВМ108
| |- Makefile - Правила сборки дерева исходников
| `- common.mk - Параметры сборки драйверов
|
`- Makefile - Правила сборки дерева исходников
```
## Сборка драйвера
- Установить и настроить [комплект разработчика](https://help.kpda.ru/help/topic/ru.kpda.doc.dev_tools/html/devkit/devkit.html) для [ЗОСРВ "Нейтрино" редакции 2020](https://help.kpda.ru/help/index.jsp).
- Выполнить команду:
```
make
```
## Запуск драйвера
```
devf-spi-s25 -s0,0 &
```

2
flash/Makefile Executable file
View File

@ -0,0 +1,2 @@
LIST=BOARD
include recurse.mk

68
flash/common.mk Executable file
View File

@ -0,0 +1,68 @@
#
# General purpose makefile for building a Neutrino flash device driver
#
ifndef QCONFIG
QCONFIG=qconfig.mk
endif
include $(QCONFIG)
INSTALLDIR=sbin
NAME = devf-$(SECTION)
EXTRA_SILENT_VARIANTS+=$(subst -, ,$(SECTION))
include ../../pinfo.mk
include $(MKFILES_ROOT)/qmacros.mk
-include $(PROJECT_ROOT)/roots.mk
#####AUTO-GENERATED by packaging script... do not checkin#####
INSTALL_ROOT_nto = $(PROJECT_ROOT)/../../../install
USE_INSTALL_ROOT=1
##############################################################
ifndef MTDFLASH_ROOT
MTDFLASH_ROOT=$(PRODUCT_ROOT)/mtd-flash
endif
EXTRA_INCVPATH += $(MTDFLASH_ROOT)/public $(PRODUCT_ROOT)
DEFLIB_VARIANT = $(subst $(space),.,$(strip a $(filter wcc be le, $(VARIANTS))))
LIB_VARIANT = $(firstword $(subst ./,,$(dir $(bind))) $(DEFLIB_VARIANT))
EXTRA_LIBVPATH += $(MTDFLASH_ROOT)/$(CPU)/$(LIB_VARIANT)
fs_ver=$(firstword $(F3S_VER) 3)
mtd_ver=$(firstword $(MTD_VER) 2)
LIB_FSFLASH=fs-flash$(fs_ver)
LIBS_COMPRESSION_2=lzo ucl
LIBS_PM=pm ps
LIBS =\
$(LIB_DEBUG)\
$(LIB_FSFLASH)\
mtd-flash\
$(LIBS_COMPRESSION_$(fs_ver))\
$(LIB_$(LIB_SUFF))
LIBS += spi-master
USEFILE = $(PROJECT_ROOT)/spi-s25/spi-s25.use
CCFLAGS += -DF3S_VER=$(fs_ver) -DMTD_VER=$(mtd_ver) -Wno-unused-variable
# If the flash filesystem headers/libraries aren't present on the system, kill
# the compiles.
ifeq ($(call FIND_HDR_DIR,nto,usr/include,fs/f3s_spec.h),)
TARGET_BUILD=@$(ECHO_HOST) Flash filesystem headers/libraries not present on system
TARGET_INSTALL=
SRCS=
endif
include $(MKFILES_ROOT)/qtargets.mk
# MUDFLAP support
#CCFLAGS+=-fmudflapth
#LDOPTS+=-fmudflapth -lmudflapth

2
flash/spi-s25/Makefile Normal file
View File

@ -0,0 +1,2 @@
LIST=CPU
include recurse.mk

36
flash/spi-s25/f3s_spi.h Normal file
View File

@ -0,0 +1,36 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#ifndef __FSLSPI_H_INCLUDED
#define __FSLSPI_H_INCLUDED
#include <sys/mman.h>
#include <sys/f3s_mtd.h>
#include <sys/neutrino.h>
#include <libc.h>
#include <hw/inout.h>
#include "s25-spi.h"
/* Freescale SPI Function Prototypes and Constant Definitions */
_int32 f3s_spi_ident( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
void f3s_spi_reset( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
int32_t f3s_spi_v2read( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset, int32_t size, uint8_t *buffer );
_int32 f3s_spi_v2write( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset, _int32 size, _uint8 *buffer );
int f3s_spi_v2erase( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
int f3s_spi_v2sync( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
int f3s_spi_v2islock( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
int f3s_spi_v2lock( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
int f3s_spi_v2unlock( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
int f3s_spi_v2unlockall( f3s_dbase_t *dbase, f3s_access_t *access, _uint32 flags, _uint32 offset );
int32_t f3s_spi_open( f3s_socket_t *socket, uint32_t flags );
uint8_t * f3s_spi_page( f3s_socket_t *socket, uint32_t page, uint32_t offset, int32_t *size );
int32_t generic_status( f3s_socket_t *socket, uint32_t flags );
void f3s_spi_close( f3s_socket_t *socket, uint32_t flags );
#endif /* __FSLSPI_H_INCLUDED */

View File

@ -0,0 +1,15 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include "f3s_spi.h"
void f3s_spi_close( f3s_socket_t *socket, uint32_t flags )
{
s25_spi_close( socket->memory );
/*s25_boot_ctrl( 0, socket->memory );*/
/*munmap_device_io( CONFIG_BOOT_BASE, SPI_REG_SIZE );*/
}

View File

@ -0,0 +1,43 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
#include <pthread.h>
#include "f3s_spi.h"
int32_t f3s_spi_ident( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
/* setup database with proper info */
/* Fill dbase entry */
dbase->struct_size = sizeof( *dbase );
dbase->jedec_hi = 0x0120;
dbase->jedec_lo = 0x184d;
dbase->name = "SPI M25";
dbase->buffer_size = PAGE_SIZE; /* buffer size information */
dbase->geo_num = 1; /* Read number of geometries */
if ( verbose > 3 )
printf( "(devf t%d::%s:%d) dbase->geo_num = %d\n", pthread_self(), __func__, __LINE__, dbase->geo_num );
dbase->geo_vect[0].unit_num = NUM_ERASE_UNITS;
dbase->geo_vect[0].unit_pow2 = PWR2_SIZE_UNIT;
if (verbose > 3)
{
printf( "(devf t%d::%s:%d) dbase->geo_vect[%d].unit_pow2 = %d\n", pthread_self(), __func__, __LINE__,
0, dbase->geo_vect[0].unit_pow2 );
printf( "(devf t%d::%s:%d) dbase->geo_vect[%d].unit_num = %d\n", pthread_self(), __func__, __LINE__,
0, dbase->geo_vect[0].unit_num );
}
/* Set bus and chip parameters */
dbase->chip_inter = flashcfg.chip_inter;
dbase->chip_width = flashcfg.bus_width;
/* Set capabilities flags */
/*dbase->flags = F3S_ERASE_FOR_ALL;*/
return (EOK);
}

View File

@ -0,0 +1,53 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include "f3s_spi.h"
extern f3s_flashcfg_t flashcfg;
int main( int argc, char **argv )
{
static f3s_service_t service[] = { { sizeof(f3s_service_t),
f3s_spi_open,
f3s_spi_page,
generic_status,
f3s_spi_close },
{ 0, 0, 0, 0, 0 /* mandatory last entry */ } };
#if MTD_VER == 2
static f3s_flash_v2_t flash[] = { { sizeof( f3s_flash_v2_t ),
f3s_spi_ident, /* Ident */
f3s_spi_reset, /* Reset */
/* v1 ReadWrite/Erase/Suspend/Resume/Sync (Unused) */
NULL, NULL, NULL, NULL, NULL, NULL,
f3s_spi_v2read, /* v2 Read (Use default) */
f3s_spi_v2write, /* v2 Write */
f3s_spi_v2erase, /* v2 Erase */
NULL, /* v2 Suspend */
NULL, /* v2 Resume */
f3s_spi_v2sync, /* v2 Sync */
/* v2 Islock/Lock/Unlock/Unlockall (not supported) */
NULL, NULL, NULL, NULL },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* mandatory last entry */ } };
#else
static f3s_flash_t flash[] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 /* mandatory last entry */ } };
#endif
/* init f3s */
f3s_init( argc, argv, (f3s_flash_t *)flash );
/* Set bus width and interleave */
set_flash_config( 8, 1 );
flashcfg.bus_width = 8;
flashcfg.chip_inter = 1;
flashcfg.device_width = flashcfg.bus_width / flashcfg.chip_inter;
/* start f3s */
return f3s_start( service, (f3s_flash_t *)flash );
}

View File

@ -0,0 +1,46 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <pthread.h>
#include "f3s_spi.h"
int32_t f3s_spi_open( f3s_socket_t *socket, uint32_t flags )
{
if ( socket->memory )
return (EOK);
ThreadCtl( _NTO_TCTL_IO, 0 );
if ( f3s_socket_option( socket ) )
{
printf( "You must use the -s option to pass in spi device number and chip select\n" );
exit( 1 );
}
s25_spi_t *spi = calloc( 1, sizeof( s25_spi_t ) );
spi->devnum = socket->address; /* using socket address field for spi device number */
spi->cs = socket->window_size; /* using socket window_size field for spi chip select */
if ( s25_spi_init( spi ) )
{
printf( "SPI init error\n" );
exit( 1 );
}
socket->memory = (_Uint8t *)spi;
char data[5];
s25_spi_id( socket->memory, data, 5 );
printf( "SPI flash: Manufacturer ID = 0x%02X, Device ID = 0x%02X%02X \n", data[0], data[1], data[2] );
socket->name = (unsigned char *)"SPI serial flash";
socket->window_size = socket->array_size = TOTAL_SIZE_BYTES;
if ( nanospin_calibrate( 0 ) != EOK )
fprintf( stderr, "(devf t%d::%s:%d) nanospin calibration failed!\n", pthread_self(), __func__, __LINE__ );
return EOK;
}

View File

@ -0,0 +1,27 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include "f3s_spi.h"
uint8_t * f3s_spi_page( f3s_socket_t *socket, uint32_t flags, uint32_t offset, int32_t *size )
{
/* check if offset does not fit in array */
if ( offset >= socket->window_size )
{
errno = ERANGE;
return (NULL);
}
/* always zero since there is only 1 window for this device */
socket->window_offset = 0;
/* ensure that offset + size is not out of bounds */
if ( size )
*size = min( *size, socket->window_size - offset );
/* memory pointers are not applicable to this device so we just return ~NULL every time the offset is within bounds */
return (uint8_t *)~((uintptr_t)NULL);
}

View File

@ -0,0 +1,12 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <pthread.h>
#include <sys/f3s_mtd.h>
void f3s_spi_reset( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
}

View File

@ -0,0 +1,20 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
#include <pthread.h>
#include "f3s_spi.h"
int f3s_spi_v2erase( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
int ret;
if ( (ret = s25_spi_erase( access->socket.memory, offset, ERASE_SECTOR )) != 0 )
fprintf( stderr, "(devf t%d::%s:%d) erase status failed for offset 0x%x, ret val %d\n",
pthread_self(), __func__, __LINE__, offset, ret );
return (EOK);
}

View File

@ -0,0 +1,12 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
int f3s_fsl_spi_v2islock( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
return (EOK);
}

View File

@ -0,0 +1,12 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
int f3s_fsl_spi_v2lock( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
return (EOK);
}

View File

@ -0,0 +1,15 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
#include <sys/neutrino.h>
#include <pthread.h>
#include "f3s_spi.h"
int32_t f3s_spi_v2read( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset, int32_t size, uint8_t *buffer )
{
return s25_spi_read( access->socket.memory, offset, buffer, size );
}

View File

@ -0,0 +1,13 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
#include "f3s_spi.h"
int32_t f3s_spi_v2sync( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
return s25_spi_wait( access->socket.memory );
}

View File

@ -0,0 +1,12 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
int f3s_fsl_spi_v2unlock( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
return (EOK);
}

View File

@ -0,0 +1,12 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
int f3s_fsl_spi_v2unlockall( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset )
{
return (EOK);
}

View File

@ -0,0 +1,15 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sys/f3s_mtd.h>
#include <sys/neutrino.h>
#include <pthread.h>
#include "f3s_spi.h"
int32_t f3s_spi_v2write( f3s_dbase_t *dbase, f3s_access_t *access, uint32_t flags, uint32_t offset, int32_t size, uint8_t *buffer )
{
return s25_spi_write( access->socket.memory, offset, buffer, size );
}

View File

@ -0,0 +1,17 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*
* This file contains the status function for the generic flash library
*/
#include "f3s_spi.h"
int32_t generic_status( f3s_socket_t *socket, uint32_t flags )
{
/* everything is fine */
return EOK;
}

2
flash/spi-s25/mips/Makefile Executable file
View File

@ -0,0 +1,2 @@
LIST=VARIANT
include recurse.mk

View File

@ -0,0 +1 @@
include ../../../common.mk

3
flash/spi-s25/pinfo.mk Normal file
View File

@ -0,0 +1,3 @@
define PINFO
PINFO DESCRIPTION= SPI flash
endef

391
flash/spi-s25/s25-spi.c Normal file
View File

@ -0,0 +1,391 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <stddef.h> /* null, size, uint */
#include <sys/mman.h>
#include <hw/inout.h>
#include <sys/neutrino.h>
#include <hw/spi-master.h>
#include "s25-spi.h"
#include <sys/slog.h>
#include <sys/slogcodes.h>
#define SPI_SET_ADDRESS( a, b ) \
do { \
uint8_t* _b = (void *)(b); \
_b[1] = (((a) >> 16) & 0xFF); \
_b[2] = (((a) >> 8) & 0xFF); \
_b[3] = (((a) >> 0) & 0xFF); \
} while ( 0 )
#define WAITTIME 30000
#define _SLOGC_FS_FLASH __C( _SLOGC_FS, 2000 )
void print_data( unsigned char *buffer, unsigned len )
{
int idx;
printf( "Data:" );
for ( idx = 0; idx < len; idx++ )
{
if ( (idx & 0x1F) == 0 )
printf( "\n" );
printf( "%02x ", buffer[idx] );
}
printf( "\n" );
}
/*
* ------------------------------
* LOWLEVEL FUNCTIONS
* ------------------------------
*/
int s25_spi_init( void *vbase )
{
s25_spi_t *spi = (s25_spi_t *)vbase;
char devname[20];
spi_cfg_t cfg;
cfg.mode = SPI_MODE_INIT_VAL;
snprintf( devname, 20, "/dev/spi%d", spi->devnum );
if ( (spi->fd = spi_open( devname )) < 0 )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "SPI open failed, device = %s, fd = %d errno = %d %s", devname, spi->fd, errno, strerror( errno ) );
return (1);
}
spi_setcfg( spi->fd, spi->cs | SPI_DEV_DEFAULT, &cfg );
return (0);
}
int s25_spi_transfer( void *vbase, int line, void *tx_, int tx_len, void *rx_, int rx_len )
{
s25_spi_t *spi = (s25_spi_t*)vbase;
int i,
status = 0,
cmd_len = (tx_len < 4 ? tx_len : 4),
xfer_len = tx_len + rx_len;
unsigned char bf1[xfer_len + 4],
bf2[xfer_len + 4],
*tx_buf = bf1,
*rx_buf = bf2;
memcpy( tx_buf, tx_, tx_len );
for ( i = tx_len; i < xfer_len; i++ )
tx_buf[i] = 0xFF;
i = spi_xchange( spi->fd, spi->cs | SPI_DEV_DEFAULT, (uint8_t *)tx_buf, (uint8_t *)rx_buf, xfer_len );
memcpy( rx_, rx_buf + tx_len, rx_len );
#if 0
printf( "SPI xfer, tx_len = %d, rx_len = %d, rsize = %d, fd = %d\n", tx_len, rx_len, i, spi->fd );
print_data( tx_buf, xfer_len );
print_data( rx_buf, xfer_len );
#endif
return i-cmd_len;
}
int s25_spi_exec( void *vbase, int line, uint8_t cmd_op, uint32_t address, uint8_t *buffer, uint32_t buf_len )
{
uint8_t cmd[4 + SPI_MAX_SIZE]; /* largest command takes 4 bytes, the data block occupies SPI_MAX_SIZE bytes */
uint8_t *in,
*out;
uint16_t in_len,
out_len;
size_t size;
int i;
cmd[0] = cmd_op; /* Save the SPI flash instruction. */
switch ( cmd_op ) /* Prepare arguments for the SPI transaction. */
{
case SPI_FLASH_RDID: /* Read identification. */
in = cmd;
in_len = 1;
out = buffer;
out_len = (buf_len > JEDEC_DATA) ? JEDEC_DATA : buf_len;
break;
case SPI_FLASH_FAST_READ: /* Read Data Bytes */
case SPI_FLASH_READ: /* Read Data Bytes */
in = cmd;
in_len = 4;
out = buffer;
out_len = (buf_len > SPI_MAX_SIZE) ? SPI_MAX_SIZE : buf_len;
SPI_SET_ADDRESS( address, cmd );
break;
case SPI_FLASH_RDSR: /* Read Status Register */
in = cmd;
in_len = 1;
out = buffer;
out_len = buf_len;
break;
case SPI_FLASH_WRSR: /* Write Status Register */
in = cmd;
in_len = 2;
out = 0;
out_len = 0;
cmd[1] = buffer[0];
break;
case SPI_FLASH_SSE: /* SubSector Erase */
case SPI_FLASH_SE: /* Sector Erase */
in = cmd;
in_len = 4;
out = 0;
out_len = 0;
SPI_SET_ADDRESS( address, cmd );
break;
case SPI_FLASH_WRDI: /* Write Disable */
case SPI_FLASH_WREN: /* Write Enable */
case SPI_FLASH_BE: /* Bulk Erase */
in = cmd;
in_len = 1;
out = 0;
out_len = 0;
break;
case SPI_FLASH_PP: /* Page Program */
size = (buf_len > PAGE_SIZE) ? PAGE_SIZE : buf_len;
in = cmd;
in_len = 4 + size;
out = 0;
out_len = 0;
SPI_SET_ADDRESS( address, cmd );
for ( i = 0; i < size; i++ )
cmd[i + 4] = buffer[i];
break;
default:
/* printf( "%s: SPI instruction %d is not provided\n", __FUNCTION__, cmd_op ); */
return (-1);
}
/* Execute the SPI transaction */
return s25_spi_transfer( vbase, line, in, in_len, out, out_len );
}
/*
* ------------------------------
* HIGH LEVEL FUNCTIONS
* ------------------------------
*/
int s25_spi_id( void *vbase, void *data, uint32_t size )
{
return s25_spi_exec( vbase, 0, SPI_FLASH_RDID, 0, data, size );
}
int s25_spi_status( void *vbase, void *status )
{
return s25_spi_exec( vbase, 0, SPI_FLASH_RDSR, 0, status, 1 );
}
int s25_spi_wren( void *vbase )
{
uint8_t status;
uint32_t timeout = WAITTIME;
s25_spi_exec( vbase, 0, SPI_FLASH_WREN, 0, 0, 0 );
s25_spi_exec( vbase, 0, SPI_FLASH_RDSR, 0, &status, 1 );
do {
if ( (timeout--) == 0 )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "Error: s25_spi_wren(WIP) timeout" );
return (-1);
}
s25_spi_exec( vbase, 0, SPI_FLASH_RDSR, 0, &status, 1 );
} while ( status & SPI_FLASH_SR_WIP );
timeout = WAITTIME;
do {
if ( (timeout--) == 0 )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "Error: s25_spi_wren timeout" );
return (-1);
}
s25_spi_exec( vbase, 0, SPI_FLASH_RDSR, 0, &status, 1 );
} while ( !(status & SPI_FLASH_SR_WEL) );
return (status & SPI_FLASH_SR_WEL) ? 0 : -1;
}
int s25_spi_wait( void *vbase )
{
uint8_t status;
uint32_t timeout = WAITTIME;
do {
if ( (timeout--) == 0 )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "Error: s25_spi_wait timeout" );
return (-1);
}
nanospin_ns( 300000 );
s25_spi_exec( vbase, 0, SPI_FLASH_RDSR, 0, &status, 1 );
} while ( status & SPI_FLASH_SR_WIP );
return (0);
}
int s25_spi_erase( void *vbase, int adr, int mode )
{
int err = s25_spi_wren( vbase );
if ( err )
return err;
if ( mode )
err = s25_spi_exec( vbase, 0, SPI_FLASH_SSE, adr, 0, 0 );
else
err = s25_spi_exec( vbase, 0, SPI_FLASH_SE, adr, 0, 0 );
if ( err < 0 )
return err;
err = s25_spi_wait( vbase );
if ( err )
return err;
return (0);
}
int s25_spi_write_page( void *vbase, int adr, void *data, uint32_t size )
{
int err,
wr_len;
err = s25_spi_wren( vbase );
if ( err )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "Error: SPI wren" );
return err;
}
wr_len = s25_spi_exec( vbase, 0, SPI_FLASH_PP, adr, data, size );
if ( wr_len != size )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "Error: SPI write" );
return wr_len;
}
err = s25_spi_wait( vbase );
if ( err )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "Error: SPI wait" );
return err;
}
return wr_len;
}
/* Flash writes must be aligned to PAGE_SIZE boundary */
int aligned_flash_write( void *vbase, unsigned offset, unsigned char *buffer, unsigned size )
{
int overflow = offset % PAGE_SIZE + size;
unsigned to_upper_border = size - (offset + size) % PAGE_SIZE;
if ( overflow > PAGE_SIZE )
{
/* Write bytes that fit in current page */
if ( s25_spi_write_page( vbase, offset, buffer, to_upper_border ) != to_upper_border )
return (-1);
/* Write left bytes in next page */
if ( s25_spi_write_page( vbase, offset + to_upper_border, buffer + to_upper_border, (offset + size) % PAGE_SIZE) != (offset + size) % PAGE_SIZE )
return (-1);
} else {
if ( s25_spi_write_page( vbase, offset, buffer, size ) != size )
return (-1);
}
return (0);
}
int s25_spi_write( void *vbase, int adr, void *buffer, int size )
{
unsigned current_offset = adr,
size_left = size;
for ( current_offset = adr; current_offset < adr + size; current_offset += PAGE_SIZE )
{
if ( size_left < PAGE_SIZE )
{
if ( aligned_flash_write( vbase, current_offset, buffer + (size - size_left), size_left ) != 0 )
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "%s %d: write status failed for offset 0x%x",
__func__, __LINE__, current_offset );
} else
if ( aligned_flash_write( vbase, current_offset, buffer + (size - size_left), PAGE_SIZE ) != 0 )
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "%s %d: write status failed for offset 0x%x",
__func__, __LINE__, current_offset );
size_left -= PAGE_SIZE;
}
return size;
}
int s25_spi_read_page( void *vbase, int adr, void *data, uint32_t size )
{
int err,
rcvd_len;
rcvd_len = s25_spi_exec( vbase, 0, SPI_FLASH_READ, adr, data, size );
if ( rcvd_len != size )
return rcvd_len;
err = s25_spi_wait( vbase );
if ( err )
{
slogf( _SLOGC_FS_FLASH, _SLOG_ERROR, "Error: SPI wait" );
return err;
}
return rcvd_len;
}
int s25_spi_read( void *vbase, int adr, void *sector, int size )
{
int rcvd_len = 0,
ret;
uint32_t cnt = size;
uint8_t *p = sector;
while ( cnt )
{
size = (cnt < SPI_MAX_SIZE) ? cnt : SPI_MAX_SIZE;
ret = s25_spi_read_page( vbase, adr, p, size );
if ( ret < size )
{
ret = s25_spi_read_page( vbase, adr, p, size );
if ( ret < size )
return (rcvd_len + ret);
}
p += ret;
adr += ret;
cnt -= ret;
rcvd_len += ret;
}
return rcvd_len;
}
void s25_spi_close( void *vbase )
{
s25_spi_t *spi = (s25_spi_t *)vbase;
spi_close( spi->fd );
/*free( spi );*/
}

179
flash/spi-s25/s25-spi.h Normal file
View File

@ -0,0 +1,179 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#ifndef __S25_SPI_H_
#define __S25_SPI_H__
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <inttypes.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stddef.h>
#include "spi_regs.h"
#include "spi_boot.h"
typedef struct s25_spi_s {
int32_t fd;
int8_t devnum;
int8_t cs;
} s25_spi_t;
#define DEVICE_IDENT "M25"
#define PAGE_SIZE 256 /* bytes */
#define SECTOR_SIZE 256 /* number of pages in one sector */
#define TOTAL_SIZE 256 /* sectors */
#define ADDR_LEN 3 /* 24 bit address */
#define CMD_LEN 1 /* one byte commands */
#define TOTAL_SIZE_BYTES (TOTAL_SIZE * SECTOR_SIZE * PAGE_SIZE)
#define SPI_MODE 0
#define DEVICE_ID 0x18
#define MAN_ID 0x20
#define NUM_ERASE_UNITS 256 /* Number of sectors, this is the erase unit */
#define PWR2_SIZE_UNIT 16
/* debug config */
#define SPI_CHECK_SAVEENV 0 /* check all sectors after u-boot cmd:saveenv */
#define SPI_LOWLEVEL_DEBUG 0 /* show lowlewel spi debug print */
/* constants */
#define SPI_FLASH_SIZE 0x1000000
#define SPI_QNX_SIZE 0xf00000
#define SPI_QNX_OFFSET 0x100000
#define SPI_SECTOR_SIZE 0x10000
#define SPI_SUBSECTOR_SIZE 0x10000
#define SPI_MAX_SIZE 0x8000
#define SPI_BAUDR_SCKDV 6 /* default baud rate and thresholds. */
#define JEDEC_DATA 20
#define MAX_SPI_TRIES 10000
#define SPI_FIFO_SIZE (CONFIG_SPI_FIFO_SIZE / sizeof( uint16_t ))
#define SPI_TH_TX (SPI_FIFO_SIZE / sizeof( uint16_t )) /* fifo threshold */
#define SPI_TH_RX (SPI_FIFO_SIZE / sizeof( uint16_t ))
#define BOOT_SPI_PORT 0
#define ERASE_SECTOR 0
#define ERASE_SUBSECTOR 1
#define SPI_MODE_INIT_VAL 0x80000403
/* SPI registers definitions */
/* SPI_SSIENR */
#define SSIENR_SSI_DE 0
#define SSIENR_SSI_EN 1
/* CTRL 0 */
/* Slave output enable. */
#define SPI_SLV_OE_OFFSET 10
#define SPI_SLV_MASK (0x1 << SPI_SLV_OE_OFFSET)
#define SPI_SLV_OE 1
/* Transfer mode bits */
#define SPI_TMOD_OFFSET 8
#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET)
#define SPI_TMOD_TR 0x0 /* transmit and receive */
#define SPI_TMOD_TO 0x1 /* transmit only */
#define SPI_TMOD_RO 0x2 /* receive only */
#define SPI_TMOD_EPROMREAD 0x3 /* EEPROM read */
/* Serial Clock Polarity. */
#define SPI_SCPOL_OFFSET 7
#define SPI_SCPOL_MASK (0x3 << SPI_SCPOL_OFFSET)
#define SPI_SCPOL_LOW 0
#define SPI_SCPOL_HIGH 1
/* Serial Clock Phase. */
#define SPI_SCPH_OFFSET 6
#define SPI_SCPH_MASK (0x3 << SPI_SCPH_OFFSET)
#define SPI_SCPH_MIDDLE 0
#define SPI_SCPH_START 1
/* Frame format. */
#define SPI_FRF_OFFSET 4
#define SPI_FRF_MASK (0x3 << SPI_FRF_OFFSET)
#define SPI_FRF_SPI 0x0
#define SPI_FRF_SSP 0x1
#define SPI_FRF_MICROWIRE 0x2
#define SPI_FRF_RESV 0x3
/* Data Frame Size */
#define SPI_DFS_OFFSET 0
#define SPI_DFS_MASK (0x3 << SPI_DFS_OFFSET)
#define SPI_DFS( x ) (x - 1)
/* Status register bits. */
#define SPI_SR_DCOL (1 << 6) /* Data Collision Error */
#define SPI_SR_TXE (1 << 5) /* Transmition Error. */
#define SPI_SR_RFF (1 << 4) /* Receive FIFO Full */
#define SPI_SR_RFNE (1 << 3) /* Receive FIFO Not Empty */
#define SPI_SR_TFE (1 << 2) /* Transmit FIFO Empty */
#define SPI_SR_TFNF (1 << 1) /* Transmit FIFO Not Full */
#define SPI_SR_BUSY (1 << 0) /* SSI Busy Flag. */
/* Define the SPI bits of the status register. */
#define SPI_FLASH_SR_WIP (1 << 0) /* Write In Progress */
#define SPI_FLASH_SR_WEL (1 << 1) /* Write Enable Latch */
/* Flag Status Register */
#define SPI_FLAG_PE (1 << 7) /* P/E Controller (not WIP) */
#define SPI_FLAG_ER_SUSPEND (1 << 6) /* Erase Suspend */
#define SPI_FLAG_ERASE (1 << 5) /* Erase */
#define SPI_FLAG_PROGRAM (1 << 4) /* Program */
#define SPI_FLAG_VPP (1 << 3) /* VPP */
#define SPI_FLAG_PR_SUSPEND (1 << 2) /* Program Suspend */
#define SPI_FLAG_PROTECTION (1 << 1) /* Protection */
#define SPI_FLAG_ (1 << 0) /* RESERVED */
/* SPI Flash commands */
#define SPI_FLASH_RDID 0x9F /* (0, 1-20) Read identification. */
#define SPI_FLASH_READ 0x03 /* (3, 1-∞ ) Read Data Bytes */
#define SPI_FLASH_FAST_READ 0x0B /* (3, 1-∞ ) Read Data Bytes */
#define SPI_FLASH_WREN 0x06 /* (0, 0 ) Write Enable */
#define SPI_FLASH_WRDI 0x04 /* (0, 0 ) Write Disable */
#define SPI_FLASH_PP 0x02 /* (3, 256 ) Page Program */
#define SPI_FLASH_SSE 0x20 /* (3, 0 ) SubSector Erase */
#define SPI_FLASH_SE 0xD8 /* (3, 0 ) Sector Erase */
#define SPI_FLASH_RDSR 0x05 /* (0, 1 ) Read Status Register */
#define SPI_FLASH_WRSR 0x01 /* (0, 1-∞ ) Write Status Register */
#define SPI_FLASH_RDLR 0xE8 /* (3, 1-∞ ) Read Lock Register */
#define SPI_FLASH_WRLR 0xE5 /* (3, 1 ) Write Lock Register */
#define SPI_FLASH_RFSR 0x70 /* (1 to ∞) Read Flag Status Register */
#define SPI_FLASH_CLFSR 0x50 /* (0) Clear Flag Status Register */
#define SPI_FLASH_BE 0xC7 /* (0) Bulk Erase */
#define SPI_FLASH_RSTEN 0x66 /* Reset Enable */
#define SPI_FLASH_RST 0x99 /* Reset Memory */
/* RDNVCR Read NV Configuration Register B5h (2) */
/* WRNVCR Write NV Configuration Register B1h (2) */
/* RDVCR Read Volatile Configuration Register 85h (1 to ∞) */
/* WRVCR Write Volatile Configuration Register 81h (1) */
/* RDVECR Read Volatile Enhanced Configuration Register 65h (1 to ∞) */
/* WRVECR Write Volatile Enhanced Configuration Register 61h (1) */
/* SPI FUNCTIONS */
int s25_spi_init( void *vbase );
int s25_spi_id( void *vbase, void *data, uint32_t size );
int s25_spi_wren( void *vbase );
int s25_spi_wait( void *vbase );
int s25_spi_erase( void *vbase, int adr, int mode );
int s25_spi_status( void *vbase, void *status );
int s25_spi_read_page( void *vbase, int adr, void *data, uint32_t size );
int s25_spi_write_page( void *vbase, int adr, void *data, uint32_t size );
int s25_spi_read( void *vbase, int adr, void *sector, int size );
int s25_spi_write( void *vbase, int adr, void *sector, int size );
void s25_spi_close( void *vbase );
int iswriting( void *vbase );
#endif /* __S25_SPI_H_ */

76
flash/spi-s25/spi-s25.use Executable file
View File

@ -0,0 +1,76 @@
%C - SPI Fast Flash File System
%C -s devnum,chipselect
[-aclrvV] [-b priority] [-f verifylevel] [-i index]
[-m mountover] [-p backgroundpercent[,superlimit]]
[-t threads] [-u updatelevel] [-w buffersize]
Options:
-s spiN,cs set SPI device number N (default: /dev/spi0) and
SPI chip select (default: 0)
-a disables all automounting/enumeration of partitions
-A all partitions are resmgr_attach() with the AFTER flag.
-E do not daemonize and exit on EBADFSYS with partition num + 1
-l list available flash databases and exit
-r enable fault recovery of dangling extents chains, partial
reclaims, dirty extent headers and damaged extent pointers
-R mount read-only
-v display verbose info
-V display file system and MTD version information
-b priority enable background reclaim at priority
(low and high are system dependant)
-f verifylevel enable flash verify (def.=0, 0=meta, write=1, erase=2, all=3)
-i arrayindex[,partindex]
set first array index and first partition index for multiple
drivers (def.=0,0 (for /fs0p0), min=0, max=15)
-m mountover
override default mountpoints assigned to file systems
formatted with an empty (ie. "") mountpoint, mountover can
include two %X format specifiers (as in printf) for the socket
index and the partition index respectively
(def.=/fs%Xp%X)
-p backgroundpercent[,superlimit]
set parameters like background reclaim percentage trigger
for stale space over free space, and superseded extent limit
before reclaim (def.=100,16)
-t threads set number of threads (def.=2, min=1, max=100)
-u updatelevel set time Update Level (def.=0, 0=never, 1=file, 2=parent)
-w buffersize set append buffer size (def.=512, 0=disable)
-L limit set flash program retry limit
-e index enumerate partitions only, automount the first <index> partitions.
-d log set log method
-k blksz set extent cache block size, default is 128k
-o file_max set the maximum numer of files to cache, default is 64
Examples:
%C -s0,0
Starts a SPI flash driver using device /dev/spi0 and SPI Chip Select 0.
%C -s0,0 -b5 -u2 -r
Starts a flash filesystem with background reclaim process enabled and
most posix semantics with an initial fault recovery when automounting.
Mountpoints:
This is for the default mountpoint index...
/fs0p0 structured flash file system mountpoint
/dev/fs0 socket mount mountpoint
/dev/fs0p0 raw partition mountpoint
%C -s0,0 -e 2
Starts the flash filesystem, automounting /dev/fs0p0, /dev/fs0p1, and /dev/fs0p2. Any
remaining partitions are only enumerated (entries created under /dev, but
no mounted filesystem).
Notes:
Hard links and access times are not supported with the flash file system.
Symbolic links, modification and change times are supported.

39
flash/spi-s25/spi_boot.h Normal file
View File

@ -0,0 +1,39 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#ifndef __S25_SPI_BOOT_H__
#define __S25_SPI_BOOT_H__
#include <sys/types.h> /* uint16_t */
#define BC_CSR (CONFIG_BOOT_BASE + 0x0)
#define BC_MAR (CONFIG_BOOT_BASE + 0x4)
#define BC_DRID (CONFIG_BOOT_BASE + 0x8)
#define BC_VID (CONFIG_BOOT_BASE + 0xC)
#define BC_MAR_VAR 1
#define BC_CSR_RDA (1 << 8)
/* control and status register */
typedef struct {
uint32_t mode :1 - 0 + 1; /* boot method */
uint32_t __ :7 - 2 + 1;
uint32_t spi_rda :8 - 8 + 1; /* operation mode: 0-transparent, 1-not transparent */
uint32_t _ :31 - 9 + 1;
} boot_csr_t;
/* memory access control register */
typedef struct {
uint32_t bsab : 0 - 0 + 1; /* reset when writing to the register */
uint32_t _ : 31 - 1 + 1;
} boot_mar_t;
void s25_boot_ctrl( int mode, void *base );
#endif /* __S25_BOOT_CNTR_H__ */

101
flash/spi-s25/spi_regs.h Normal file
View File

@ -0,0 +1,101 @@
/*
* (c) 2021, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#ifndef __S25_SPI_REG_H_
#define __S25_SPI_REG_H__
#include <sys/types.h> /* uint16_t */
/* ctrl0 */
typedef struct {
uint32_t dfs :4; /* data frame size */
uint32_t frf :2; /* frame format (0-spi, 1-ssp, 2-micro, 3-reserved) */
uint32_t scph :1; /* clk phase */
uint32_t scpol :1; /* clk polarity */
uint32_t tmod :2; /* transfer mode (0-tx|rx, 1-tx, 2-rx, 3-eeprom) */
uint32_t slv_oe :1; /* (ignore) slave output enable */
uint32_t srl :1; /* (ignore) shift register loop */
uint32_t cfs :4; /* (ignore) control frame size */
uint32_t _ :16;
} spi_ctrlr0_t;
typedef uint32_t spi_ctrlr1_t;
typedef uint32_t spi_ssienr_t;
typedef uint32_t spi_mwcr_t;
typedef uint32_t spi_ser_t;
typedef uint32_t spi_baudr_t;
typedef uint32_t spi_txftlr_t;
typedef uint32_t spi_rxftlr_t;
typedef uint32_t spi_txflr_t;
typedef uint32_t spi_rxflr_t;
/* status register */
typedef struct {
uint32_t busy :1; /* busy */
uint32_t tfnf :1; /* transmite fifo not full */
uint32_t tfe :1; /* transmite fifo empty */
uint32_t rfne :1; /* recieve fifo not empty */
uint32_t rff :1; /* recieve fifo full */
uint32_t txe :1; /* transmission error */
uint32_t dcol :1; /* data collision error */
uint32_t _ :2;
uint32_t __ :8 * 3;
} spi_sr_t;
typedef uint32_t spi_imr_t;
typedef uint32_t spi_is_t;
typedef uint32_t spi_risr_t;
typedef uint32_t spi_txoicr_t;
typedef uint32_t spi_rxoicr_t;
typedef uint32_t spi_rxuicr_t;
typedef uint32_t spi_msticr_t;
typedef uint32_t spi_icr_t;
typedef uint32_t spi_dmacr_t;
typedef uint32_t spi_dmatdlr_t;
typedef uint32_t spi_dmardlr_t;
typedef uint32_t spi_idr_t;
typedef uint32_t spi_ssi_version_id_t;
typedef uint32_t spi_dr0_t;
typedef uint32_t spi_dr35_t;
typedef uint32_t spi_rx_sample_dly_t;
typedef uint32_t spi_rsvd_0_t;
typedef uint32_t spi_rsvd_1_t;
typedef uint32_t spi_rsvd_2_t;
/* MACROS TO ACCESS REGISTERS */
#define SPI_REG_CTRLR0( p ) (*(volatile spi_ctrlr0_t *)SPI_CTRLR0( p ))
#define SPI_REG_CTRLR1( p ) (*(volatile spi_ctrlr1_t *)SPI_CTRLR1( p ))
#define SPI_REG_SSIENR( p ) (*(volatile spi_ssienr_t *)SPI_SSIENR( p ))
#define SPI_REG_MWCR( p ) (*(volatile spi_mwcr_t *)SPI_MWCR( p ))
#define SPI_REG_SER( p ) (*(volatile spi_ser_t *)SPI_SER( p ))
#define SPI_REG_BAUDR( p ) (*(volatile spi_baudr_t *)SPI_BAUDR( p ))
#define SPI_REG_TXFTLR( p ) (*(volatile spi_txftlr_t *)SPI_TXFTLR( p ))
#define SPI_REG_RXFTLR( p ) (*(volatile spi_rxftlr_t *)SPI_RXFTLR( p ))
#define SPI_REG_TXFLR( p ) (*(volatile spi_txflr_t *)SPI_TXFLR( p ))
#define SPI_REG_RXFLR( p ) (*(volatile spi_rxflr_t *)SPI_RXFLR( p ))
#define SPI_REG_SR( p ) (*(volatile spi_sr_t *)SPI_SR( p ))
#define SPI_REG_IMR( p ) (*(volatile spi_imr_t *)SPI_IMR( p ))
#define SPI_REG_IS( p ) (*(volatile spi_is_t *)SPI_IS( p ))
#define SPI_REG_RISR( p ) (*(volatile spi_risr_t *)SPI_RISR( p ))
#define SPI_REG_TXOICR( p ) (*(volatile spi_txoicr_t *)SPI_TXOICR( p ))
#define SPI_REG_RXOICR( p ) (*(volatile spi_rxoicr_t *)SPI_RXOICR( p ))
#define SPI_REG_RXUICR( p ) (*(volatile spi_rxuicr_t *)SPI_RXUICR( p ))
#define SPI_REG_MSTICR( p ) (*(volatile spi_msticr_t *)SPI_MSTICR( p ))
#define SPI_REG_ICR( p ) (*(volatile spi_icr_t *)SPI_ICR( p ))
#define SPI_REG_DMACR( p ) (*(volatile spi_dmacr_t *)SPI_DMACR( p ))
#define SPI_REG_DMATDLR( p ) (*(volatile spi_dmatdlr_t *)SPI_DMATDLR( p ))
#define SPI_REG_DMARDLR( p ) (*(volatile spi_dmardlr_t *)SPI_DMARDLR( p ))
#define SPI_REG_IDR( p ) (*(volatile spi_idr_t *)SPI_IDR( p ))
#define SPI_REG_SSI_VERSION_ID( p ) (*(volatile spi_ssi_version_id_t *)SPI_SSI_VERSION_ID( p ))
#define SPI_REG_DR( p ) (*(volatile spi_dr0_t *)SPI_DR0( p ))
#define SPI_REG_RX_SAMPLE_DLY( p ) (*(volatile spi_rx_sample_dly_t *)SPI_RX_SAMPLE_DLY( p ))
#define SPI_REG_RSVD_0( p ) (*(volatile spi_rsvd_0_t *)SPI_RSVD_0( p ))
#define SPI_REG_RSVD_1( p ) (*(volatile spi_rsvd_1_t *)SPI_RSVD_1( p ))
#define SPI_REG_RSVD_2( p ) (*(volatile spi_rsvd_2_t *)SPI_RSVD_2( p ))
#endif /* __S25_SPI_REG_H__ */