Message ID | cac44f4d9ed06e250c2fa8aa900d8de3de4c4337.1686557139.git.Takahiro.Kuwano@infineon.com |
---|---|
State | Changes Requested |
Delegated to: | Ambarus Tudor |
Headers | show |
Series | mtd: spi-nor: spansion: Add support for Infineon S28HS02GT | expand |
On 6/12/23 11:04, tkuw584924@gmail.com wrote: > From: Takahiro Kuwano <Takahiro.Kuwano@infineon.com> > > S28HS02GT is multi-chip package (MCP) device that requires Octal DTR > configuraion for each die. We can access to configuration registers in each > die by using params->n_dice and params->vreg_offset[] populated from SFDP. I wonder if we really need to differentiate between the MCP and single chip package flashes. Do the single chip flashes that are currently supported in spansion.c and support Octal DDR define the params->n_dice and params->vreg_offset[]? Do they have the necessary SFDP tables?
Hi Takahiro, Hi Miquel, > S28HS02GT is multi-chip package (MCP) device that requires Octal DTR > configuraion for each die. We can access to configuration registers in > each > die by using params->n_dice and params->vreg_offset[] populated from > SFDP. I'm looking into cleaning up the flash db and come across the n_banks and n_dice parameter. Which sounds like they seem to be similar, maybe identical? Unfortunately, there is no public datasheet for the macronix flash.. IIRC there is one for the Semperflashes but I'm not sure if there is one for the MCP parts. Could we somehow clarify if these are the same properties? I've looked at the SFDP tables of the macronix flash and they don't have the SCCR map for multi chip devices :/ -michael
Hi Michael, On 7/18/2023 7:49 AM, Michael Walle wrote: > Hi Takahiro, Hi Miquel, > >> S28HS02GT is multi-chip package (MCP) device that requires Octal DTR >> configuraion for each die. We can access to configuration registers in each >> die by using params->n_dice and params->vreg_offset[] populated from SFDP. > > I'm looking into cleaning up the flash db and come across the n_banks > and n_dice parameter. Which sounds like they seem to be similar, maybe > identical? Unfortunately, there is no public datasheet for the macronix > flash.. IIRC there is one for the Semperflashes but I'm not sure if there > is one for the MCP parts. > Could we somehow clarify if these are the same properties? I've looked at > the SFDP tables of the macronix flash and they don't have the SCCR map for > multi chip devices :/ > > -michael The n_banks and n_dice are different properties. One die can contain multiple banks. Infineon does not have multi-bank parts that support RWW. The SEMPER MCP parts do not support RWW on different die. Thanks, Takahiro
Hi, >>> S28HS02GT is multi-chip package (MCP) device that requires Octal DTR >>> configuraion for each die. We can access to configuration registers >>> in each >>> die by using params->n_dice and params->vreg_offset[] populated from >>> SFDP. >> >> I'm looking into cleaning up the flash db and come across the n_banks >> and n_dice parameter. Which sounds like they seem to be similar, maybe >> identical? Unfortunately, there is no public datasheet for the >> macronix >> flash.. IIRC there is one for the Semperflashes but I'm not sure if >> there >> is one for the MCP parts. >> Could we somehow clarify if these are the same properties? I've looked >> at >> the SFDP tables of the macronix flash and they don't have the SCCR map >> for >> multi chip devices :/ >> >> -michael > > The n_banks and n_dice are different properties. One die can contain > multiple > banks. Infineon does not have multi-bank parts that support RWW. The > SEMPER > MCP parts do not support RWW on different die. Ok. thanks for the quick answer! -michael
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c index 0daa3a357ae8..eda3731c17be 100644 --- a/drivers/mtd/spi-nor/spansion.c +++ b/drivers/mtd/spi-nor/spansion.c @@ -156,7 +156,7 @@ static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor) return 1; } -static int cypress_nor_setup_memlat(struct spi_nor *nor) +static int cypress_nor_setup_memlat(struct spi_nor *nor, u64 addr) { struct spi_mem_op op; u8 *buf = nor->bouncebuf; @@ -164,8 +164,7 @@ static int cypress_nor_setup_memlat(struct spi_nor *nor) u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; op = (struct spi_mem_op) - CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR2V, 0, buf); + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, buf); ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); if (ret) @@ -175,13 +174,12 @@ static int cypress_nor_setup_memlat(struct spi_nor *nor) *buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK; *buf |= SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR2V, 1, buf); + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1, buf); return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); } -static int cypress_nor_setup_opiddr(struct spi_nor *nor, bool enable) +static int cypress_nor_setup_opiddr(struct spi_nor *nor, u64 addr, bool enable) { struct spi_mem_op op; u8 *buf = nor->bouncebuf; @@ -191,8 +189,7 @@ static int cypress_nor_setup_opiddr(struct spi_nor *nor, bool enable) buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN; op = (struct spi_mem_op) CYPRESS_NOR_WR_ANY_REG_OP(nor->params->addr_mode_nbytes, - SPINOR_REG_CYPRESS_CFR5V, 1, - buf); + addr, 1, buf); } else { /* * The register is 1-byte wide, but 1-byte transactions are not @@ -203,8 +200,7 @@ static int cypress_nor_setup_opiddr(struct spi_nor *nor, bool enable) buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS; buf[1] = 0; op = (struct spi_mem_op) - CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, - SPINOR_REG_CYPRESS_CFR5V, 2, + CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, addr, 2, buf); } @@ -600,6 +596,49 @@ static struct spi_nor_fixups s25hx_t_fixups = { .late_init = s25hx_t_late_init, }; +static int cypress_nor_octal_dtr_enable_single_chip(struct spi_nor *nor, + bool enable) +{ + int ret; + + if (enable) { + ret = cypress_nor_setup_memlat(nor, SPINOR_REG_CYPRESS_CFR2V); + if (ret) + return ret; + + nor->read_dummy = 24; + } + + return cypress_nor_setup_opiddr(nor, SPINOR_REG_CYPRESS_CFR5V, enable); +} + +static int cypress_nor_octal_dtr_enable_mcp(struct spi_nor *nor, bool enable) +{ + struct spi_nor_flash_parameter *params = nor->params; + u64 addr; + u8 i; + int ret; + + if (enable) { + for (i = 0; i < params->n_dice; i++) { + addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR2; + ret = cypress_nor_setup_memlat(nor, addr); + if (ret) + return ret; + } + nor->read_dummy = 24; + } + + for (i = 0; i < params->n_dice; i++) { + addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5; + ret = cypress_nor_setup_opiddr(nor, addr, enable); + if (ret) + return ret; + } + + return 0; +} + /** * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes. * @nor: pointer to a 'struct spi_nor' @@ -616,15 +655,11 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) u8 naddr, ndummy; enum spi_nor_protocol proto; - if (enable) { - ret = cypress_nor_setup_memlat(nor); - if (ret) - return ret; - - nor->read_dummy = 24; - } + if (nor->params->n_dice) + ret = cypress_nor_octal_dtr_enable_mcp(nor, enable); + else + ret = cypress_nor_octal_dtr_enable_single_chip(nor, enable); - ret = cypress_nor_setup_opiddr(nor, enable); if (ret) return ret;