mtd: spi-nor: introduce SPI 1-2-2 and SPI 1-4-4 protocols
This patch changes the prototype of spi_nor_scan(): its 3rd parameter is replaced by a 'struct spi_nor_hwcaps' pointer, which tells the spi-nor framework about the actual hardware capabilities supported by the SPI controller and its driver. Besides, this patch also introduces a new 'struct spi_nor_flash_parameter' telling the spi-nor framework about the hardware capabilities supported by the SPI flash memory and the associated settings required to use those hardware caps. Then, to improve the readability of spi_nor_scan(), the discovery of the memory settings and the memory initialization are now split into two dedicated functions. 1 - spi_nor_init_params() The spi_nor_init_params() function is responsible for initializing the 'struct spi_nor_flash_parameter'. Currently this structure is filled with legacy values but further patches will allow to override some parameter values dynamically, for instance by reading the JESD216 Serial Flash Discoverable Parameter (SFDP) tables from the SPI memory. The spi_nor_init_params() function only deals with the hardware capabilities of the SPI flash memory: especially it doesn't care about the hardware capabilities supported by the SPI controller. 2 - spi_nor_setup() The second function is called once the 'struct spi_nor_flash_parameter' has been initialized by spi_nor_init_params(). With both 'struct spi_nor_flash_parameter' and 'struct spi_nor_hwcaps', the new argument of spi_nor_scan(), spi_nor_setup() computes the best match between hardware caps supported by both the (Q)SPI memory and controller hence selecting the relevant settings for (Fast) Read and Page Program operations. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Reviewed-by: Marek Vasut <marek.vasut@gmail.com>
This commit is contained in:

committed by
Cyrille Pitchen

parent
2ea659a9ef
commit
cfc5604c48
@@ -275,14 +275,48 @@ static void atmel_qspi_debug_command(struct atmel_qspi *aq,
|
||||
|
||||
static int atmel_qspi_run_command(struct atmel_qspi *aq,
|
||||
const struct atmel_qspi_command *cmd,
|
||||
u32 ifr_tfrtyp, u32 ifr_width)
|
||||
u32 ifr_tfrtyp, enum spi_nor_protocol proto)
|
||||
{
|
||||
u32 iar, icr, ifr, sr;
|
||||
int err = 0;
|
||||
|
||||
iar = 0;
|
||||
icr = 0;
|
||||
ifr = ifr_tfrtyp | ifr_width;
|
||||
ifr = ifr_tfrtyp;
|
||||
|
||||
/* Set the SPI protocol */
|
||||
switch (proto) {
|
||||
case SNOR_PROTO_1_1_1:
|
||||
ifr |= QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
|
||||
break;
|
||||
|
||||
case SNOR_PROTO_1_1_2:
|
||||
ifr |= QSPI_IFR_WIDTH_DUAL_OUTPUT;
|
||||
break;
|
||||
|
||||
case SNOR_PROTO_1_1_4:
|
||||
ifr |= QSPI_IFR_WIDTH_QUAD_OUTPUT;
|
||||
break;
|
||||
|
||||
case SNOR_PROTO_1_2_2:
|
||||
ifr |= QSPI_IFR_WIDTH_DUAL_IO;
|
||||
break;
|
||||
|
||||
case SNOR_PROTO_1_4_4:
|
||||
ifr |= QSPI_IFR_WIDTH_QUAD_IO;
|
||||
break;
|
||||
|
||||
case SNOR_PROTO_2_2_2:
|
||||
ifr |= QSPI_IFR_WIDTH_DUAL_CMD;
|
||||
break;
|
||||
|
||||
case SNOR_PROTO_4_4_4:
|
||||
ifr |= QSPI_IFR_WIDTH_QUAD_CMD;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Compute instruction parameters */
|
||||
if (cmd->enable.bits.instruction) {
|
||||
@@ -434,7 +468,7 @@ static int atmel_qspi_read_reg(struct spi_nor *nor, u8 opcode,
|
||||
cmd.rx_buf = buf;
|
||||
cmd.buf_len = len;
|
||||
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ,
|
||||
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
|
||||
nor->reg_proto);
|
||||
}
|
||||
|
||||
static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
|
||||
@@ -450,7 +484,7 @@ static int atmel_qspi_write_reg(struct spi_nor *nor, u8 opcode,
|
||||
cmd.tx_buf = buf;
|
||||
cmd.buf_len = len;
|
||||
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
|
||||
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
|
||||
nor->reg_proto);
|
||||
}
|
||||
|
||||
static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
|
||||
@@ -469,7 +503,7 @@ static ssize_t atmel_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
|
||||
cmd.tx_buf = write_buf;
|
||||
cmd.buf_len = len;
|
||||
ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE_MEM,
|
||||
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
|
||||
nor->write_proto);
|
||||
return (ret < 0) ? ret : len;
|
||||
}
|
||||
|
||||
@@ -484,7 +518,7 @@ static int atmel_qspi_erase(struct spi_nor *nor, loff_t offs)
|
||||
cmd.instruction = nor->erase_opcode;
|
||||
cmd.address = (u32)offs;
|
||||
return atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_WRITE,
|
||||
QSPI_IFR_WIDTH_SINGLE_BIT_SPI);
|
||||
nor->reg_proto);
|
||||
}
|
||||
|
||||
static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
|
||||
@@ -493,27 +527,8 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
|
||||
struct atmel_qspi *aq = nor->priv;
|
||||
struct atmel_qspi_command cmd;
|
||||
u8 num_mode_cycles, num_dummy_cycles;
|
||||
u32 ifr_width;
|
||||
ssize_t ret;
|
||||
|
||||
switch (nor->flash_read) {
|
||||
case SPI_NOR_NORMAL:
|
||||
case SPI_NOR_FAST:
|
||||
ifr_width = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
|
||||
break;
|
||||
|
||||
case SPI_NOR_DUAL:
|
||||
ifr_width = QSPI_IFR_WIDTH_DUAL_OUTPUT;
|
||||
break;
|
||||
|
||||
case SPI_NOR_QUAD:
|
||||
ifr_width = QSPI_IFR_WIDTH_QUAD_OUTPUT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nor->read_dummy >= 2) {
|
||||
num_mode_cycles = 2;
|
||||
num_dummy_cycles = nor->read_dummy - 2;
|
||||
@@ -536,7 +551,7 @@ static ssize_t atmel_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
|
||||
cmd.rx_buf = read_buf;
|
||||
cmd.buf_len = len;
|
||||
ret = atmel_qspi_run_command(aq, &cmd, QSPI_IFR_TFRTYP_TRSFR_READ_MEM,
|
||||
ifr_width);
|
||||
nor->read_proto);
|
||||
return (ret < 0) ? ret : len;
|
||||
}
|
||||
|
||||
@@ -590,6 +605,20 @@ static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
|
||||
|
||||
static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct spi_nor_hwcaps hwcaps = {
|
||||
.mask = SNOR_HWCAPS_READ |
|
||||
SNOR_HWCAPS_READ_FAST |
|
||||
SNOR_HWCAPS_READ_1_1_2 |
|
||||
SNOR_HWCAPS_READ_1_2_2 |
|
||||
SNOR_HWCAPS_READ_2_2_2 |
|
||||
SNOR_HWCAPS_READ_1_1_4 |
|
||||
SNOR_HWCAPS_READ_1_4_4 |
|
||||
SNOR_HWCAPS_READ_4_4_4 |
|
||||
SNOR_HWCAPS_PP |
|
||||
SNOR_HWCAPS_PP_1_1_4 |
|
||||
SNOR_HWCAPS_PP_1_4_4 |
|
||||
SNOR_HWCAPS_PP_4_4_4,
|
||||
};
|
||||
struct device_node *child, *np = pdev->dev.of_node;
|
||||
struct atmel_qspi *aq;
|
||||
struct resource *res;
|
||||
@@ -679,7 +708,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto disable_clk;
|
||||
|
||||
err = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
|
||||
err = spi_nor_scan(nor, NULL, &hwcaps);
|
||||
if (err)
|
||||
goto disable_clk;
|
||||
|
||||
|
Reference in New Issue
Block a user