aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/mtd/spi-nor/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/spi-nor/core.c')
-rw-r--r--drivers/mtd/spi-nor/core.c86
1 files changed, 54 insertions, 32 deletions
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index b07e66f10995..877557dbda7f 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -778,7 +778,7 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
ret = spi_nor_read_cr(nor, &sr_cr[1]);
if (ret)
return ret;
- } else if (nor->params.quad_enable) {
+ } else if (nor->params->quad_enable) {
/*
* If the Status Register 2 Read command (35h) is not
* supported, we should at least be sure we don't
@@ -786,7 +786,7 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
*
* We can safely assume that when the Quad Enable method is
* set, the value of the QE bit is one, as a consequence of the
- * nor->params.quad_enable() call.
+ * nor->params->quad_enable() call.
*
* We can safely assume that the Quad Enable bit is present in
* the Status Register 2 at BIT(1). According to the JESD216
@@ -1051,6 +1051,11 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode)
ARRAY_SIZE(spi_nor_3to4_erase));
}
+static bool spi_nor_has_uniform_erase(const struct spi_nor *nor)
+{
+ return !!nor->params->erase_map.uniform_erase_type;
+}
+
static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
{
nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
@@ -1058,7 +1063,7 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode);
if (!spi_nor_has_uniform_erase(nor)) {
- struct spi_nor_erase_map *map = &nor->params.erase_map;
+ struct spi_nor_erase_map *map = &nor->params->erase_map;
struct spi_nor_erase_type *erase;
int i;
@@ -1095,10 +1100,10 @@ void spi_nor_unlock_and_unprep(struct spi_nor *nor)
static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr)
{
- if (!nor->params.convert_addr)
+ if (!nor->params->convert_addr)
return addr;
- return nor->params.convert_addr(nor, addr);
+ return nor->params->convert_addr(nor, addr);
}
/*
@@ -1203,6 +1208,16 @@ spi_nor_find_best_erase_type(const struct spi_nor_erase_map *map,
return NULL;
}
+static u64 spi_nor_region_is_last(const struct spi_nor_erase_region *region)
+{
+ return region->offset & SNOR_LAST_REGION;
+}
+
+static u64 spi_nor_region_end(const struct spi_nor_erase_region *region)
+{
+ return (region->offset & ~SNOR_ERASE_FLAGS_MASK) + region->size;
+}
+
/**
* spi_nor_region_next() - get the next spi nor region
* @region: pointer to a structure that describes a SPI NOR erase region
@@ -1307,7 +1322,7 @@ static int spi_nor_init_erase_cmd_list(struct spi_nor *nor,
struct list_head *erase_list,
u64 addr, u32 len)
{
- const struct spi_nor_erase_map *map = &nor->params.erase_map;
+ const struct spi_nor_erase_map *map = &nor->params->erase_map;
const struct spi_nor_erase_type *erase, *prev_erase = NULL;
struct spi_nor_erase_region *region;
struct spi_nor_erase_command *cmd = NULL;
@@ -1793,7 +1808,7 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
if (ret)
return ret;
- ret = nor->params.locking_ops->lock(nor, ofs, len);
+ ret = nor->params->locking_ops->lock(nor, ofs, len);
spi_nor_unlock_and_unprep(nor);
return ret;
@@ -1808,7 +1823,7 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
if (ret)
return ret;
- ret = nor->params.locking_ops->unlock(nor, ofs, len);
+ ret = nor->params->locking_ops->unlock(nor, ofs, len);
spi_nor_unlock_and_unprep(nor);
return ret;
@@ -1823,7 +1838,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
if (ret)
return ret;
- ret = nor->params.locking_ops->is_locked(nor, ofs, len);
+ ret = nor->params->locking_ops->is_locked(nor, ofs, len);
spi_nor_unlock_and_unprep(nor);
return ret;
@@ -2288,7 +2303,7 @@ static int spi_nor_spimem_check_pp(struct spi_nor *nor,
static void
spi_nor_spimem_adjust_hwcaps(struct spi_nor *nor, u32 *hwcaps)
{
- struct spi_nor_flash_parameter *params = &nor->params;
+ struct spi_nor_flash_parameter *params = nor->params;
unsigned int cap;
/* DTR modes are not supported yet, mask them all. */
@@ -2387,7 +2402,7 @@ static int spi_nor_select_read(struct spi_nor *nor,
if (cmd < 0)
return -EINVAL;
- read = &nor->params.reads[cmd];
+ read = &nor->params->reads[cmd];
nor->read_opcode = read->opcode;
nor->read_proto = read->proto;
@@ -2418,7 +2433,7 @@ static int spi_nor_select_pp(struct spi_nor *nor,
if (cmd < 0)
return -EINVAL;
- pp = &nor->params.page_programs[cmd];
+ pp = &nor->params->page_programs[cmd];
nor->program_opcode = pp->opcode;
nor->write_proto = pp->proto;
return 0;
@@ -2479,7 +2494,7 @@ spi_nor_select_uniform_erase(struct spi_nor_erase_map *map,
static int spi_nor_select_erase(struct spi_nor *nor)
{
- struct spi_nor_erase_map *map = &nor->params.erase_map;
+ struct spi_nor_erase_map *map = &nor->params->erase_map;
const struct spi_nor_erase_type *erase = NULL;
struct mtd_info *mtd = &nor->mtd;
u32 wanted_size = nor->info->sector_size;
@@ -2528,7 +2543,7 @@ static int spi_nor_select_erase(struct spi_nor *nor)
static int spi_nor_default_setup(struct spi_nor *nor,
const struct spi_nor_hwcaps *hwcaps)
{
- struct spi_nor_flash_parameter *params = &nor->params;
+ struct spi_nor_flash_parameter *params = nor->params;
u32 ignored_mask, shared_mask;
int err;
@@ -2589,10 +2604,10 @@ static int spi_nor_default_setup(struct spi_nor *nor,
static int spi_nor_setup(struct spi_nor *nor,
const struct spi_nor_hwcaps *hwcaps)
{
- if (!nor->params.setup)
+ if (!nor->params->setup)
return 0;
- return nor->params.setup(nor, hwcaps);
+ return nor->params->setup(nor, hwcaps);
}
/**
@@ -2622,13 +2637,13 @@ static void spi_nor_sfdp_init_params(struct spi_nor *nor)
{
struct spi_nor_flash_parameter sfdp_params;
- memcpy(&sfdp_params, &nor->params, sizeof(sfdp_params));
+ memcpy(&sfdp_params, nor->params, sizeof(sfdp_params));
if (spi_nor_parse_sfdp(nor, &sfdp_params)) {
nor->addr_width = 0;
nor->flags &= ~SNOR_F_4B_OPCODES;
} else {
- memcpy(&nor->params, &sfdp_params, sizeof(nor->params));
+ memcpy(nor->params, &sfdp_params, sizeof(*nor->params));
}
}
@@ -2639,7 +2654,7 @@ static void spi_nor_sfdp_init_params(struct spi_nor *nor)
*/
static void spi_nor_info_init_params(struct spi_nor *nor)
{
- struct spi_nor_flash_parameter *params = &nor->params;
+ struct spi_nor_flash_parameter *params = nor->params;
struct spi_nor_erase_map *map = &params->erase_map;
const struct flash_info *info = nor->info;
struct device_node *np = spi_nor_get_flash_node(nor);
@@ -2758,8 +2773,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
* NOR protection support. When locking_ops are not provided, we pick
* the default ones.
*/
- if (nor->flags & SNOR_F_HAS_LOCK && !nor->params.locking_ops)
- nor->params.locking_ops = &spi_nor_sr_locking_ops;
+ if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops)
+ nor->params->locking_ops = &spi_nor_sr_locking_ops;
}
/**
@@ -2799,8 +2814,12 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
* ->default_init() hook or the SFDP parser do not set specific params.
* spi_nor_late_init_params()
*/
-static void spi_nor_init_params(struct spi_nor *nor)
+static int spi_nor_init_params(struct spi_nor *nor)
{
+ nor->params = devm_kzalloc(nor->dev, sizeof(*nor->params), GFP_KERNEL);
+ if (!nor->params)
+ return -ENOMEM;
+
spi_nor_info_init_params(nor);
spi_nor_manufacturer_init_params(nor);
@@ -2812,6 +2831,8 @@ static void spi_nor_init_params(struct spi_nor *nor)
spi_nor_post_sfdp_fixups(nor);
spi_nor_late_init_params(nor);
+
+ return 0;
}
/**
@@ -2822,14 +2843,14 @@ static void spi_nor_init_params(struct spi_nor *nor)
*/
static int spi_nor_quad_enable(struct spi_nor *nor)
{
- if (!nor->params.quad_enable)
+ if (!nor->params->quad_enable)
return 0;
if (!(spi_nor_get_protocol_width(nor->read_proto) == 4 ||
spi_nor_get_protocol_width(nor->write_proto) == 4))
return 0;
- return nor->params.quad_enable(nor);
+ return nor->params->quad_enable(nor);
}
/**
@@ -2844,7 +2865,7 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
static int spi_nor_unlock_all(struct spi_nor *nor)
{
if (nor->flags & SNOR_F_HAS_LOCK)
- return spi_nor_unlock(&nor->mtd, 0, nor->params.size);
+ return spi_nor_unlock(&nor->mtd, 0, nor->params->size);
return 0;
}
@@ -2875,7 +2896,7 @@ static int spi_nor_init(struct spi_nor *nor)
*/
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
"enabling reset hack; may not recover from unexpected reboots\n");
- nor->params.set_4byte_addr_mode(nor, true);
+ nor->params->set_4byte_addr_mode(nor, true);
}
return 0;
@@ -2899,7 +2920,7 @@ void spi_nor_restore(struct spi_nor *nor)
/* restore the addressing mode */
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
- nor->params.set_4byte_addr_mode(nor, false);
+ nor->params->set_4byte_addr_mode(nor, false);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);
@@ -3004,7 +3025,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
struct device *dev = nor->dev;
struct mtd_info *mtd = &nor->mtd;
struct device_node *np = spi_nor_get_flash_node(nor);
- struct spi_nor_flash_parameter *params = &nor->params;
int ret;
int i;
@@ -3055,7 +3075,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
mtd->_write = spi_nor_write;
/* Init flash parameters based on flash_info struct and SFDP */
- spi_nor_init_params(nor);
+ ret = spi_nor_init_params(nor);
+ if (ret)
+ return ret;
if (!mtd->name)
mtd->name = dev_name(dev);
@@ -3063,12 +3085,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
mtd->type = MTD_NORFLASH;
mtd->writesize = 1;
mtd->flags = MTD_CAP_NORFLASH;
- mtd->size = params->size;
+ mtd->size = nor->params->size;
mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read;
mtd->_resume = spi_nor_resume;
- if (nor->params.locking_ops) {
+ if (nor->params->locking_ops) {
mtd->_lock = spi_nor_lock;
mtd->_unlock = spi_nor_unlock;
mtd->_is_locked = spi_nor_is_locked;
@@ -3091,7 +3113,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
mtd->flags |= MTD_NO_ERASE;
mtd->dev.parent = dev;
- nor->page_size = params->page_size;
+ nor->page_size = nor->params->page_size;
mtd->writebufsize = nor->page_size;
if (of_property_read_bool(np, "broken-flash-reset"))