mirror of
https://github.com/smaeul/u-boot.git
synced 2025-10-13 20:36:02 +01:00
mtd: spi-nor: Use spi-mem dirmap API
This adds support for the dirmap API to the spi-nor subsystem, as introduced in Linux commit df5c21002cf4 ("mtd: spi-nor: use spi-mem dirmap API"). This patch is synchronize from the following patch https://patchwork.ozlabs.org/project/uboot/patch/20210205043924.149504-4-seanga2@gmail.com/ The corresponding Linux kernel SHA1 is df5c21002cf4. Signed-off-by: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com> Signed-off-by: Sean Anderson <seanga2@gmail.com> Acked-by: Pratyush Yadav <p.yadav@ti.com>
This commit is contained in:
parent
f7e1de4c6a
commit
463cdf6663
@ -10,13 +10,69 @@
|
|||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <linux/mtd/spi-nor.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <spi.h>
|
#include <spi.h>
|
||||||
#include <spi_flash.h>
|
#include <spi_flash.h>
|
||||||
|
#include <spi-mem.h>
|
||||||
|
|
||||||
#include "sf_internal.h"
|
#include "sf_internal.h"
|
||||||
|
|
||||||
|
static int spi_nor_create_read_dirmap(struct spi_nor *nor)
|
||||||
|
{
|
||||||
|
struct spi_mem_dirmap_info info = {
|
||||||
|
.op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0),
|
||||||
|
SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
|
||||||
|
SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
|
||||||
|
SPI_MEM_OP_DATA_IN(0, NULL, 0)),
|
||||||
|
.offset = 0,
|
||||||
|
.length = nor->mtd.size,
|
||||||
|
};
|
||||||
|
struct spi_mem_op *op = &info.op_tmpl;
|
||||||
|
|
||||||
|
/* get transfer protocols. */
|
||||||
|
spi_nor_setup_op(nor, op, nor->read_proto);
|
||||||
|
op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
|
||||||
|
|
||||||
|
/* convert the dummy cycles to the number of bytes */
|
||||||
|
op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8;
|
||||||
|
if (spi_nor_protocol_is_dtr(nor->read_proto))
|
||||||
|
op->dummy.nbytes *= 2;
|
||||||
|
|
||||||
|
nor->dirmap.rdesc = spi_mem_dirmap_create(nor->spi, &info);
|
||||||
|
if (IS_ERR(nor->dirmap.rdesc))
|
||||||
|
return PTR_ERR(nor->dirmap.rdesc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_nor_create_write_dirmap(struct spi_nor *nor)
|
||||||
|
{
|
||||||
|
struct spi_mem_dirmap_info info = {
|
||||||
|
.op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0),
|
||||||
|
SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
|
||||||
|
SPI_MEM_OP_NO_DUMMY,
|
||||||
|
SPI_MEM_OP_DATA_OUT(0, NULL, 0)),
|
||||||
|
.offset = 0,
|
||||||
|
.length = nor->mtd.size,
|
||||||
|
};
|
||||||
|
struct spi_mem_op *op = &info.op_tmpl;
|
||||||
|
|
||||||
|
/* get transfer protocols. */
|
||||||
|
spi_nor_setup_op(nor, op, nor->write_proto);
|
||||||
|
op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
|
||||||
|
|
||||||
|
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
|
||||||
|
op->addr.nbytes = 0;
|
||||||
|
|
||||||
|
nor->dirmap.wdesc = spi_mem_dirmap_create(nor->spi, &info);
|
||||||
|
if (IS_ERR(nor->dirmap.wdesc))
|
||||||
|
return PTR_ERR(nor->dirmap.wdesc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_flash_probe_slave() - Probe for a SPI flash device on a bus
|
* spi_flash_probe_slave() - Probe for a SPI flash device on a bus
|
||||||
*
|
*
|
||||||
@ -45,6 +101,16 @@ static int spi_flash_probe_slave(struct spi_flash *flash)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_read_id;
|
goto err_read_id;
|
||||||
|
|
||||||
|
if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
|
||||||
|
ret = spi_nor_create_read_dirmap(flash);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = spi_nor_create_write_dirmap(flash);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
|
if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
|
||||||
ret = spi_flash_mtd_register(flash);
|
ret = spi_flash_mtd_register(flash);
|
||||||
|
|
||||||
@ -83,6 +149,11 @@ struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
|
|||||||
|
|
||||||
void spi_flash_free(struct spi_flash *flash)
|
void spi_flash_free(struct spi_flash *flash)
|
||||||
{
|
{
|
||||||
|
if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
|
||||||
|
spi_mem_dirmap_destroy(flash->dirmap.wdesc);
|
||||||
|
spi_mem_dirmap_destroy(flash->dirmap.rdesc);
|
||||||
|
}
|
||||||
|
|
||||||
if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
|
if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
|
||||||
spi_flash_mtd_unregister(flash);
|
spi_flash_mtd_unregister(flash);
|
||||||
|
|
||||||
@ -153,6 +224,11 @@ static int spi_flash_std_remove(struct udevice *dev)
|
|||||||
struct spi_flash *flash = dev_get_uclass_priv(dev);
|
struct spi_flash *flash = dev_get_uclass_priv(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (CONFIG_IS_ENABLED(SPI_DIRMAP)) {
|
||||||
|
spi_mem_dirmap_destroy(flash->dirmap.wdesc);
|
||||||
|
spi_mem_dirmap_destroy(flash->dirmap.rdesc);
|
||||||
|
}
|
||||||
|
|
||||||
ret = spi_nor_remove(flash);
|
ret = spi_nor_remove(flash);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -246,9 +246,9 @@ static u8 spi_nor_get_cmd_ext(const struct spi_nor *nor,
|
|||||||
* need to be initialized.
|
* need to be initialized.
|
||||||
* @proto: the protocol from which the properties need to be set.
|
* @proto: the protocol from which the properties need to be set.
|
||||||
*/
|
*/
|
||||||
static void spi_nor_setup_op(const struct spi_nor *nor,
|
void spi_nor_setup_op(const struct spi_nor *nor,
|
||||||
struct spi_mem_op *op,
|
struct spi_mem_op *op,
|
||||||
const enum spi_nor_protocol proto)
|
const enum spi_nor_protocol proto)
|
||||||
{
|
{
|
||||||
u8 ext;
|
u8 ext;
|
||||||
|
|
||||||
@ -369,13 +369,29 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
|
|||||||
|
|
||||||
while (remaining) {
|
while (remaining) {
|
||||||
op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
|
op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
|
||||||
ret = spi_mem_adjust_op_size(nor->spi, &op);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = spi_mem_exec_op(nor->spi, &op);
|
if (CONFIG_IS_ENABLED(SPI_DIRMAP) && nor->dirmap.rdesc) {
|
||||||
if (ret)
|
/*
|
||||||
return ret;
|
* Record current operation information which may be used
|
||||||
|
* when the address or data length exceeds address mapping.
|
||||||
|
*/
|
||||||
|
memcpy(&nor->dirmap.rdesc->info.op_tmpl, &op,
|
||||||
|
sizeof(struct spi_mem_op));
|
||||||
|
ret = spi_mem_dirmap_read(nor->dirmap.rdesc,
|
||||||
|
op.addr.val, op.data.nbytes,
|
||||||
|
op.data.buf.in);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
op.data.nbytes = ret;
|
||||||
|
} else {
|
||||||
|
ret = spi_mem_adjust_op_size(nor->spi, &op);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = spi_mem_exec_op(nor->spi, &op);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
op.addr.val += op.data.nbytes;
|
op.addr.val += op.data.nbytes;
|
||||||
remaining -= op.data.nbytes;
|
remaining -= op.data.nbytes;
|
||||||
@ -400,14 +416,21 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
|
|||||||
|
|
||||||
spi_nor_setup_op(nor, &op, nor->write_proto);
|
spi_nor_setup_op(nor, &op, nor->write_proto);
|
||||||
|
|
||||||
ret = spi_mem_adjust_op_size(nor->spi, &op);
|
if (CONFIG_IS_ENABLED(SPI_DIRMAP) && nor->dirmap.wdesc) {
|
||||||
if (ret)
|
memcpy(&nor->dirmap.wdesc->info.op_tmpl, &op,
|
||||||
return ret;
|
sizeof(struct spi_mem_op));
|
||||||
op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
|
op.data.nbytes = spi_mem_dirmap_write(nor->dirmap.wdesc, op.addr.val,
|
||||||
|
op.data.nbytes, op.data.buf.out);
|
||||||
|
} else {
|
||||||
|
ret = spi_mem_adjust_op_size(nor->spi, &op);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
|
||||||
|
|
||||||
ret = spi_mem_exec_op(nor->spi, &op);
|
ret = spi_mem_exec_op(nor->spi, &op);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return op.data.nbytes;
|
return op.data.nbytes;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/mtd/cfi.h>
|
#include <linux/mtd/cfi.h>
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
|
#include <spi-mem.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Manufacturer IDs
|
* Manufacturer IDs
|
||||||
@ -522,6 +523,7 @@ struct spi_flash {
|
|||||||
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
|
* @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
|
||||||
* @octal_dtr_enable: [FLASH-SPECIFIC] enables SPI NOR octal DTR mode.
|
* @octal_dtr_enable: [FLASH-SPECIFIC] enables SPI NOR octal DTR mode.
|
||||||
* @ready: [FLASH-SPECIFIC] check if the flash is ready
|
* @ready: [FLASH-SPECIFIC] check if the flash is ready
|
||||||
|
* @dirmap: pointers to struct spi_mem_dirmap_desc for reads/writes.
|
||||||
* @priv: the private data
|
* @priv: the private data
|
||||||
*/
|
*/
|
||||||
struct spi_nor {
|
struct spi_nor {
|
||||||
@ -572,6 +574,11 @@ struct spi_nor {
|
|||||||
int (*octal_dtr_enable)(struct spi_nor *nor);
|
int (*octal_dtr_enable)(struct spi_nor *nor);
|
||||||
int (*ready)(struct spi_nor *nor);
|
int (*ready)(struct spi_nor *nor);
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct spi_mem_dirmap_desc *rdesc;
|
||||||
|
struct spi_mem_dirmap_desc *wdesc;
|
||||||
|
} dirmap;
|
||||||
|
|
||||||
void *priv;
|
void *priv;
|
||||||
char mtd_name[MTD_NAME_SIZE(MTD_DEV_TYPE_NOR)];
|
char mtd_name[MTD_NAME_SIZE(MTD_DEV_TYPE_NOR)];
|
||||||
/* Compatibility for spi_flash, remove once sf layer is merged with mtd */
|
/* Compatibility for spi_flash, remove once sf layer is merged with mtd */
|
||||||
@ -595,6 +602,17 @@ device_node *spi_nor_get_flash_node(struct spi_nor *nor)
|
|||||||
}
|
}
|
||||||
#endif /* __UBOOT__ */
|
#endif /* __UBOOT__ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spi_nor_setup_op() - Set up common properties of a spi-mem op.
|
||||||
|
* @nor: pointer to a 'struct spi_nor'
|
||||||
|
* @op: pointer to the 'struct spi_mem_op' whose properties
|
||||||
|
* need to be initialized.
|
||||||
|
* @proto: the protocol from which the properties need to be set.
|
||||||
|
*/
|
||||||
|
void spi_nor_setup_op(const struct spi_nor *nor,
|
||||||
|
struct spi_mem_op *op,
|
||||||
|
const enum spi_nor_protocol proto);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_nor_scan() - scan the SPI NOR
|
* spi_nor_scan() - scan the SPI NOR
|
||||||
* @nor: the spi_nor structure
|
* @nor: the spi_nor structure
|
||||||
|
Loading…
x
Reference in New Issue
Block a user