diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c index 9d43e18d3770..b3b11dfed789 100644 --- a/drivers/mtd/spi-nor/sfdp.c +++ b/drivers/mtd/spi-nor/sfdp.c @@ -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 @@ static int spi_nor_parse_sccr(struct spi_nor *nor, 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; }