@ -16,6 +16,7 @@
# include <spi.h>
# include <spi_flash.h>
# include <linux/log2.h>
# include <linux/sizes.h>
# include <dma.h>
# include "sf_internal.h"
@ -541,6 +542,164 @@ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
}
# ifdef CONFIG_SPI_FLASH_SST
static bool sst26_process_bpr ( u32 bpr_size , u8 * cmd , u32 bit , enum lock_ctl ctl )
{
switch ( ctl ) {
case SST26_CTL_LOCK :
cmd [ bpr_size - ( bit / 8 ) - 1 ] | = BIT ( bit % 8 ) ;
break ;
case SST26_CTL_UNLOCK :
cmd [ bpr_size - ( bit / 8 ) - 1 ] & = ~ BIT ( bit % 8 ) ;
break ;
case SST26_CTL_CHECK :
return ! ! ( cmd [ bpr_size - ( bit / 8 ) - 1 ] & BIT ( bit % 8 ) ) ;
}
return false ;
}
/*
* sst26wf016 / sst26wf032 / sst26wf064 have next block protection :
* 4 x - 8 KByte blocks - read & write protection bits - upper addresses
* 1 x - 32 KByte blocks - write protection bits
* rest - 64 KByte blocks - write protection bits
* 1 x - 32 KByte blocks - write protection bits
* 4 x - 8 KByte blocks - read & write protection bits - lower addresses
*
* We ' ll support only per 64 k lock / unlock so lower and upper 64 KByte region
* will be treated as single block .
*/
/*
* Lock , unlock or check lock status of the flash region of the flash ( depending
* on the lock_ctl value )
*/
static int sst26_lock_ctl ( struct spi_flash * flash , u32 ofs , size_t len , enum lock_ctl ctl )
{
u32 i , bpr_ptr , rptr_64k , lptr_64k , bpr_size ;
bool lower_64k = false , upper_64k = false ;
u8 cmd , bpr_buff [ SST26_MAX_BPR_REG_LEN ] = { } ;
int ret ;
/* Check length and offset for 64k alignment */
if ( ( ofs & ( SZ_64K - 1 ) ) | | ( len & ( SZ_64K - 1 ) ) )
return - EINVAL ;
if ( ofs + len > flash - > size )
return - EINVAL ;
/* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */
if ( flash - > size ! = SZ_2M & &
flash - > size ! = SZ_4M & &
flash - > size ! = SZ_8M )
return - EINVAL ;
bpr_size = 2 + ( flash - > size / SZ_64K / 8 ) ;
cmd = SST26_CMD_READ_BPR ;
ret = spi_flash_read_common ( flash , & cmd , 1 , bpr_buff , bpr_size ) ;
if ( ret < 0 ) {
printf ( " SF: fail to read block-protection register \n " ) ;
return ret ;
}
rptr_64k = min_t ( u32 , ofs + len , flash - > size - SST26_BOUND_REG_SIZE ) ;
lptr_64k = max_t ( u32 , ofs , SST26_BOUND_REG_SIZE ) ;
upper_64k = ( ( ofs + len ) > ( flash - > size - SST26_BOUND_REG_SIZE ) ) ;
lower_64k = ( ofs < SST26_BOUND_REG_SIZE ) ;
/* Lower bits in block-protection register are about 64k region */
bpr_ptr = lptr_64k / SZ_64K - 1 ;
/* Process 64K blocks region */
while ( lptr_64k < rptr_64k ) {
if ( sst26_process_bpr ( bpr_size , bpr_buff , bpr_ptr , ctl ) )
return EACCES ;
bpr_ptr + + ;
lptr_64k + = SZ_64K ;
}
/* 32K and 8K region bits in BPR are after 64k region bits */
bpr_ptr = ( flash - > size - 2 * SST26_BOUND_REG_SIZE ) / SZ_64K ;
/* Process lower 32K block region */
if ( lower_64k )
if ( sst26_process_bpr ( bpr_size , bpr_buff , bpr_ptr , ctl ) )
return EACCES ;
bpr_ptr + + ;
/* Process upper 32K block region */
if ( upper_64k )
if ( sst26_process_bpr ( bpr_size , bpr_buff , bpr_ptr , ctl ) )
return EACCES ;
bpr_ptr + + ;
/* Process lower 8K block regions */
for ( i = 0 ; i < SST26_BPR_8K_NUM ; i + + ) {
if ( lower_64k )
if ( sst26_process_bpr ( bpr_size , bpr_buff , bpr_ptr , ctl ) )
return EACCES ;
/* In 8K area BPR has both read and write protection bits */
bpr_ptr + = 2 ;
}
/* Process upper 8K block regions */
for ( i = 0 ; i < SST26_BPR_8K_NUM ; i + + ) {
if ( upper_64k )
if ( sst26_process_bpr ( bpr_size , bpr_buff , bpr_ptr , ctl ) )
return EACCES ;
/* In 8K area BPR has both read and write protection bits */
bpr_ptr + = 2 ;
}
/* If we check region status we don't need to write BPR back */
if ( ctl = = SST26_CTL_CHECK )
return 0 ;
cmd = SST26_CMD_WRITE_BPR ;
ret = spi_flash_write_common ( flash , & cmd , 1 , bpr_buff , bpr_size ) ;
if ( ret < 0 ) {
printf ( " SF: fail to write block-protection register \n " ) ;
return ret ;
}
return 0 ;
}
static int sst26_unlock ( struct spi_flash * flash , u32 ofs , size_t len )
{
return sst26_lock_ctl ( flash , ofs , len , SST26_CTL_UNLOCK ) ;
}
static int sst26_lock ( struct spi_flash * flash , u32 ofs , size_t len )
{
return sst26_lock_ctl ( flash , ofs , len , SST26_CTL_LOCK ) ;
}
/*
* Returns EACCES ( positive value ) if region is locked , 0 if region is unlocked ,
* and negative on errors .
*/
static int sst26_is_locked ( struct spi_flash * flash , u32 ofs , size_t len )
{
/*
* is_locked function is used for check before reading or erasing flash
* region , so offset and length might be not 64 k allighned , so adjust
* them to be 64 k allighned as sst26_lock_ctl works only with 64 k
* allighned regions .
*/
ofs - = ofs & ( SZ_64K - 1 ) ;
len = len & ( SZ_64K - 1 ) ? ( len & ~ ( SZ_64K - 1 ) ) + SZ_64K : len ;
return sst26_lock_ctl ( flash , ofs , len , SST26_CTL_CHECK ) ;
}
static int sst_byte_write ( struct spi_flash * flash , u32 offset , const void * buf )
{
struct spi_slave * spi = flash - > spi ;
@ -1033,6 +1192,15 @@ int spi_flash_scan(struct spi_flash *flash)
}
# endif
/* sst26wf series block protection implementation differs from other series */
# if defined(CONFIG_SPI_FLASH_SST)
if ( JEDEC_MFR ( info ) = = SPI_FLASH_CFI_MFR_SST & & info - > id [ 1 ] = = 0x26 ) {
flash - > flash_lock = sst26_lock ;
flash - > flash_unlock = sst26_unlock ;
flash - > flash_is_locked = sst26_is_locked ;
}
# endif
/* Compute the flash size */
flash - > shift = ( flash - > dual_flash & SF_DUAL_PARALLEL_FLASH ) ? 1 : 0 ;
flash - > page_size = info - > page_size ;