Драйвер devf-spi-s25 для ЗОСРВ Нейтрино редакции 2020
Этот коммит содержится в:
Коммит
8105ec52ab
|
@ -0,0 +1,2 @@
|
|||
LIST=hardware
|
||||
include recurse.mk
|
|
@ -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 &
|
||||
```
|
|
@ -0,0 +1,2 @@
|
|||
LIST=BOARD
|
||||
include recurse.mk
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
LIST=CPU
|
||||
include recurse.mk
|
|
@ -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 */
|
|
@ -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 );*/
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 )
|
||||
{
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
LIST=VARIANT
|
||||
include recurse.mk
|
|
@ -0,0 +1 @@
|
|||
include ../../../common.mk
|
|
@ -0,0 +1,3 @@
|
|||
define PINFO
|
||||
PINFO DESCRIPTION= SPI flash
|
||||
endef
|
|
@ -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 );*/
|
||||
}
|
|
@ -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_ */
|
|
@ -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.
|
|
@ -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__ */
|
|
@ -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__ */
|
Загрузка…
Ссылка в новой задаче