UPSTREAM: sf: Add a method to obtain the block-protect setting

It is useful to obtain the block-protect setting of the SPI flash, so we
know whether it is fully open or (perhaps partially) write-protected. Add
a method for this. Update the sandbox driver to process this operation and
add a test.

Signed-off-by: Simon Glass <sjg@chromium.org
Change-Id: I8e8abe197ab483a26622f02666cc234a1544e642
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
(cherry picked from commit a58986ca8b53d8c7a441397082f84edc7f47d19f)
This commit is contained in:
Simon Glass 2018-11-06 15:21:41 -07:00 committed by Kever Yang
parent 59beb0b0a8
commit b6e92505d5
8 changed files with 149 additions and 0 deletions

View File

@ -79,4 +79,35 @@ long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time);
int sandbox_usb_keyb_add_string(struct udevice *dev, const char *str);
/**
* sandbox_osd_get_mem() - get the internal memory of a sandbox OSD
*
* @dev: OSD device for which to access the internal memory for
* @buf: pointer to buffer to receive the OSD memory data
* @buflen: length of buffer in bytes
*/
int sandbox_osd_get_mem(struct udevice *dev, u8 *buf, size_t buflen);
/**
* sandbox_pwm_get_config() - get the PWM config for a channel
*
* @dev: Device to check
* @channel: Channel number to check
* @period_ns: Period of the PWM in nanoseconds
* @duty_ns: Current duty cycle of the PWM in nanoseconds
* @enable: true if the PWM is enabled
* @polarity: true if the PWM polarity is active high
* @return 0 if OK, -ENOSPC if the PWM number is invalid
*/
int sandbox_pwm_get_config(struct udevice *dev, uint channel, uint *period_nsp,
uint *duty_nsp, bool *enablep, bool *polarityp);
/**
* sandbox_sf_set_block_protect() - Set the BP bits of the status register
*
* @dev: Device to update
* @bp_mask: BP bits to set (bits 2:0, so a value of 0 to 7)
*/
void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask);
#endif

View File

@ -59,6 +59,8 @@ static const char *sandbox_sf_state_name(enum sandbox_sf_state state)
/* Bits for the status register */
#define STAT_WIP (1 << 0)
#define STAT_WEL (1 << 1)
#define STAT_BP_SHIFT 2
#define STAT_BP_MASK (7 << STAT_BP_SHIFT)
/* Assume all SPI flashes have 3 byte addresses since they do atm */
#define SF_ADDR_LEN 3
@ -104,6 +106,14 @@ struct sandbox_spi_flash_plat_data {
int cs;
};
void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask)
{
struct sandbox_spi_flash *sbsf = dev_get_priv(dev);
sbsf->status &= ~STAT_BP_MASK;
sbsf->status |= bp_mask << STAT_BP_SHIFT;
}
/**
* This is a very strange probe function. If it has platform data (which may
* have come from the device tree) then this function gets the filename and

View File

@ -29,6 +29,15 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len)
return log_ret(sf_get_ops(dev)->erase(dev, offset, len));
}
int spl_flash_get_sw_write_prot(struct udevice *dev)
{
struct dm_spi_flash_ops *ops = sf_get_ops(dev);
if (!ops->get_sw_write_prot)
return -ENOSYS;
return log_ret(ops->get_sw_write_prot(dev));
}
/*
* TODO(sjg@chromium.org): This is an old-style function. We should remove
* it when all SPI flash drivers use dm

View File

@ -172,6 +172,9 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
/* Flash erase(sectors) operation, support all possible erase commands */
int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len);
/* Get software write-protect value (BP bits) */
int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash);
/* Lock stmicro spi flash region */
int stm_lock(struct spi_flash *flash, u32 ofs, size_t len);

View File

@ -125,6 +125,13 @@ static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
return spi_flash_cmd_erase_ops(flash, offset, len);
}
static int spi_flash_std_get_sw_write_prot(struct udevice *dev)
{
struct spi_flash *flash = dev_get_uclass_priv(dev);
return spi_flash_cmd_get_sw_write_prot(flash);
}
static int spi_flash_std_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parent_priv(dev);
@ -142,6 +149,7 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = {
.read = spi_flash_std_read,
.write = spi_flash_std_write,
.erase = spi_flash_std_erase,
.get_sw_write_prot = spi_flash_std_get_sw_write_prot,
};
static const struct udevice_id spi_flash_std_ids[] = {

View File

@ -113,6 +113,18 @@ static int write_cr(struct spi_flash *flash, u8 wc)
}
#endif
int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash)
{
u8 status;
int ret;
ret = read_sr(flash, &status);
if (ret)
return ret;
return (status >> 2) & 7;
}
#ifdef CONFIG_SPI_FLASH_BAR
/*
* This "clean_bar" is necessary in a situation when one was accessing

View File

@ -113,6 +113,19 @@ struct dm_spi_flash_ops {
int (*write)(struct udevice *dev, u32 offset, size_t len,
const void *buf);
int (*erase)(struct udevice *dev, u32 offset, size_t len);
/**
* get_sw_write_prot() - Check state of software write-protect feature
*
* SPI flash chips can lock a region of the flash defined by a
* 'protected area'. This function checks if this protected area is
* defined.
*
* @dev: SPI flash device
* @return 0 if no region is write-protected, 1 if a region is
* write-protected, -ENOSYS if the driver does not implement this,
* other -ve value on error
*/
int (*get_sw_write_prot)(struct udevice *dev);
};
/* Access the serial operations for a device */
@ -154,6 +167,20 @@ int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len,
*/
int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len);
/**
* spl_flash_get_sw_write_prot() - Check state of software write-protect feature
*
* SPI flash chips can lock a region of the flash defined by a
* 'protected area'. This function checks if this protected area is
* defined.
*
* @dev: SPI flash device
* @return 0 if no region is write-protected, 1 if a region is
* write-protected, -ENOSYS if the driver does not implement this,
* other -ve value on error
*/
int spl_flash_get_sw_write_prot(struct udevice *dev);
int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode,
struct udevice **devp);

View File

@ -10,12 +10,61 @@
#include <spi.h>
#include <spi_flash.h>
#include <asm/state.h>
#include <asm/test.h>
#include <dm/test.h>
#include <dm/util.h>
#include <test/ut.h>
/* Test that sandbox SPI flash works correctly */
static int dm_test_spi_flash(struct unit_test_state *uts)
{
struct udevice *dev, *emul;
int full_size = 0x200000;
int size = 0x10000;
u8 *src, *dst;
int i;
src = map_sysmem(0x20000, full_size);
ut_assertok(os_write_file("spi.bin", src, full_size));
ut_assertok(uclass_first_device_err(UCLASS_SPI_FLASH, &dev));
dst = map_sysmem(0x20000 + full_size, full_size);
ut_assertok(spi_flash_read_dm(dev, 0, size, dst));
ut_assertok(memcmp(src, dst, size));
/* Erase */
ut_assertok(spi_flash_erase_dm(dev, 0, size));
ut_assertok(spi_flash_read_dm(dev, 0, size, dst));
for (i = 0; i < size; i++)
ut_asserteq(dst[i], 0xff);
/* Write some new data */
for (i = 0; i < size; i++)
src[i] = i;
ut_assertok(spi_flash_write_dm(dev, 0, size, src));
ut_assertok(spi_flash_read_dm(dev, 0, size, dst));
ut_assertok(memcmp(src, dst, size));
/* Try the write-protect stuff */
ut_assertok(uclass_first_device_err(UCLASS_SPI_EMUL, &emul));
ut_asserteq(0, spl_flash_get_sw_write_prot(dev));
sandbox_sf_set_block_protect(emul, 1);
ut_asserteq(1, spl_flash_get_sw_write_prot(dev));
sandbox_sf_set_block_protect(emul, 0);
ut_asserteq(0, spl_flash_get_sw_write_prot(dev));
/*
* Since we are about to destroy all devices, we must tell sandbox
* to forget the emulation device
*/
sandbox_sf_unbind_emul(state_get_current(), 0, 0);
return 0;
}
DM_TEST(dm_test_spi_flash, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Functional test that sandbox SPI flash works correctly */
static int dm_test_spi_flash_func(struct unit_test_state *uts)
{
/*
* Create an empty test file and run the SPI flash tests. This is a