mtd: spi-nor: sfdp: Add support for SCCR map for multi-chip device

SCCR map for multi-chip devices contains the number of additional dice in
the device and register offset values for each additional dice.

spi_nor_parse_sccr_mc() is added to determine the number of dice and
volatile register offset for each die. The volatile register offset table
may already be allocated and contains offset value for die-0 via SCCR map
parse. So, we should use devm_krealloc() to expand the table with
preserving die-0 offset.

Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com>
Link: https://lore.kernel.org/r/89c892d52f8cbddbd14373f6a02db496885ae4f1.1680849425.git.Takahiro.Kuwano@infineon.com
Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
This commit is contained in:
Takahiro Kuwano 2023-04-07 15:41:00 +09:00 committed by Tudor Ambarus
parent 706fd00da0
commit 7ab8b81075
No known key found for this signature in database
GPG Key ID: 4B554F47A58D14E9
1 changed files with 66 additions and 0 deletions

View File

@ -26,6 +26,11 @@
* Status, Control and Configuration
* Register Map.
*/
#define SFDP_SCCR_MAP_MC_ID 0xff88 /*
* Status, Control and Configuration
* Register Map Offsets for Multi-Chip
* SPI Memory Devices.
*/
#define SFDP_SIGNATURE 0x50444653U
@ -1264,6 +1269,63 @@ out:
return ret;
}
/**
* spi_nor_parse_sccr_mc() - Parse the Status, Control and Configuration
* Register Map Offsets for Multi-Chip SPI Memory
* Devices.
* @nor: pointer to a 'struct spi_nor'
* @sccr_mc_header: pointer to the 'struct sfdp_parameter_header' describing
* the SCCR Map offsets table length and version.
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_parse_sccr_mc(struct spi_nor *nor,
const struct sfdp_parameter_header *sccr_mc_header)
{
struct spi_nor_flash_parameter *params = nor->params;
u32 *dwords, addr;
u8 i, n_dice;
size_t len;
int ret;
len = sccr_mc_header->length * sizeof(*dwords);
dwords = kmalloc(len, GFP_KERNEL);
if (!dwords)
return -ENOMEM;
addr = SFDP_PARAM_HEADER_PTP(sccr_mc_header);
ret = spi_nor_read_sfdp(nor, addr, len, dwords);
if (ret)
goto out;
le32_to_cpu_array(dwords, sccr_mc_header->length);
/*
* Pair of DOWRDs (volatile and non-volatile register offsets) per
* additional die. Hence, length = 2 * (number of additional dice).
*/
n_dice = 1 + sccr_mc_header->length / 2;
/* Address offset for volatile registers of additional dice */
params->vreg_offset =
devm_krealloc(nor->dev, params->vreg_offset,
n_dice * sizeof(*dwords),
GFP_KERNEL);
if (!params->vreg_offset) {
ret = -ENOMEM;
goto out;
}
for (i = 1; i < n_dice; i++)
params->vreg_offset[i] = dwords[SFDP_DWORD(i) * 2];
params->n_dice = n_dice;
out:
kfree(dwords);
return ret;
}
/**
* spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings
* after SFDP has been parsed. Called only for flashes that define JESD216 SFDP
@ -1480,6 +1542,10 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
err = spi_nor_parse_sccr(nor, param_header);
break;
case SFDP_SCCR_MAP_MC_ID:
err = spi_nor_parse_sccr_mc(nor, param_header);
break;
default:
break;
}