[PATCH 09/13] spi: intel-dg: implement mtd access handlers
Alexander Usyskin
alexander.usyskin at intel.com
Thu Mar 28 05:22:32 PDT 2024
Implement mtd read, erase, and write handlers.
For erase operation address and size should be 4K aligned.
For write operation address and size has to be 4bytes aligned.
CC: Rodrigo Vivi <rodrigo.vivi at intel.com>
CC: Lucas De Marchi <lucas.demarchi at intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler at intel.com>
Signed-off-by: Vitaly Lubart <vitaly.lubart at intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin at intel.com>
---
drivers/spi/spi-intel-dg.c | 152 +++++++++++++++++++++++++++++++++++--
1 file changed, 147 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-intel-dg.c b/drivers/spi/spi-intel-dg.c
index 4af8a2314fc7..9e8be7713f1a 100644
--- a/drivers/spi/spi-intel-dg.c
+++ b/drivers/spi/spi-intel-dg.c
@@ -174,7 +174,6 @@ static int intel_dg_spi_is_valid(struct intel_dg_spi *spi)
return 0;
}
-__maybe_unused
static unsigned int spi_get_region(const struct intel_dg_spi *spi, loff_t from)
{
unsigned int i;
@@ -206,7 +205,6 @@ static ssize_t spi_rewrite_partial(struct intel_dg_spi *spi, loff_t to,
return len;
}
-__maybe_unused
static ssize_t spi_write(struct intel_dg_spi *spi, u8 region,
loff_t to, size_t len, const unsigned char *buf)
{
@@ -265,7 +263,6 @@ static ssize_t spi_write(struct intel_dg_spi *spi, u8 region,
return len;
}
-__maybe_unused
static ssize_t spi_read(struct intel_dg_spi *spi, u8 region,
loff_t from, size_t len, unsigned char *buf)
{
@@ -324,7 +321,6 @@ static ssize_t spi_read(struct intel_dg_spi *spi, u8 region,
return len;
}
-__maybe_unused
static ssize_t
spi_erase(struct intel_dg_spi *spi, u8 region, loff_t from, u64 len, u64 *fail_addr)
{
@@ -413,18 +409,164 @@ static int intel_dg_spi_init(struct intel_dg_spi *spi, struct device *device)
static int intel_dg_spi_erase(struct mtd_info *mtd, struct erase_info *info)
{
- return 0;
+ struct intel_dg_spi *spi;
+ unsigned int idx;
+ u8 region;
+ u64 addr;
+ ssize_t bytes;
+ loff_t from;
+ size_t len;
+ size_t total_len;
+ int ret = 0;
+
+ if (!mtd || !info)
+ return -EINVAL;
+
+ spi = mtd->priv;
+ if (WARN_ON(!spi))
+ return -EINVAL;
+
+ if (!IS_ALIGNED(info->addr, SZ_4K) || !IS_ALIGNED(info->len, SZ_4K)) {
+ dev_err(&mtd->dev, "unaligned erase %llx %llx\n",
+ info->addr, info->len);
+ info->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+ return -EINVAL;
+ }
+
+ total_len = info->len;
+ addr = info->addr;
+
+ mutex_lock(&spi->lock);
+
+ while (total_len > 0) {
+ if (!IS_ALIGNED(addr, SZ_4K) || !IS_ALIGNED(total_len, SZ_4K)) {
+ dev_err(&mtd->dev, "unaligned erase %llx %zx\n", addr, total_len);
+ info->fail_addr = addr;
+ ret = -ERANGE;
+ goto out;
+ }
+
+ idx = spi_get_region(spi, addr);
+ if (idx >= spi->nregions) {
+ dev_err(&mtd->dev, "out of range");
+ info->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
+ ret = -ERANGE;
+ goto out;
+ }
+
+ from = addr - spi->regions[idx].offset;
+ region = spi->regions[idx].id;
+ len = total_len;
+ if (len > spi->regions[idx].size - from)
+ len = spi->regions[idx].size - from;
+
+ dev_dbg(&mtd->dev, "erasing region[%d] %s from %llx len %zx\n",
+ region, spi->regions[idx].name, from, len);
+
+ bytes = spi_erase(spi, region, from, len, &info->fail_addr);
+ if (bytes < 0) {
+ dev_dbg(&mtd->dev, "erase failed with %zd\n", bytes);
+ info->fail_addr += spi->regions[idx].offset;
+ ret = bytes;
+ goto out;
+ }
+
+ addr += len;
+ total_len -= len;
+ }
+
+out:
+ mutex_unlock(&spi->lock);
+ return ret;
}
static int intel_dg_spi_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
+ struct intel_dg_spi *spi;
+ ssize_t ret;
+ unsigned int idx;
+ u8 region;
+
+ if (!mtd)
+ return -EINVAL;
+
+ spi = mtd->priv;
+ if (WARN_ON(!spi))
+ return -EINVAL;
+
+ idx = spi_get_region(spi, from);
+
+ dev_dbg(&mtd->dev, "reading region[%d] %s from %lld len %zd\n",
+ spi->regions[idx].id, spi->regions[idx].name, from, len);
+
+ if (idx >= spi->nregions) {
+ dev_err(&mtd->dev, "out of ragnge");
+ return -ERANGE;
+ }
+
+ from -= spi->regions[idx].offset;
+ region = spi->regions[idx].id;
+ if (len > spi->regions[idx].size - from)
+ len = spi->regions[idx].size - from;
+
+ mutex_lock(&spi->lock);
+
+ ret = spi_read(spi, region, from, len, buf);
+ if (ret < 0) {
+ dev_dbg(&mtd->dev, "read failed with %zd\n", ret);
+ mutex_unlock(&spi->lock);
+ return ret;
+ }
+
+ *retlen = ret;
+
+ mutex_unlock(&spi->lock);
return 0;
}
static int intel_dg_spi_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
+ struct intel_dg_spi *spi;
+ ssize_t ret;
+ unsigned int idx;
+ u8 region;
+
+ if (!mtd)
+ return -EINVAL;
+
+ spi = mtd->priv;
+ if (WARN_ON(!spi))
+ return -EINVAL;
+
+ idx = spi_get_region(spi, to);
+
+ dev_dbg(&mtd->dev, "writing region[%d] %s to %lld len %zd\n",
+ spi->regions[idx].id, spi->regions[idx].name, to, len);
+
+ if (idx >= spi->nregions) {
+ dev_err(&mtd->dev, "out of range");
+ return -ERANGE;
+ }
+
+ to -= spi->regions[idx].offset;
+ region = spi->regions[idx].id;
+ if (len > spi->regions[idx].size - to)
+ len = spi->regions[idx].size - to;
+
+ mutex_lock(&spi->lock);
+
+ ret = spi_write(spi, region, to, len, buf);
+ if (ret < 0) {
+ dev_dbg(&mtd->dev, "write failed with %zd\n", ret);
+ mutex_unlock(&spi->lock);
+ return ret;
+ }
+
+ *retlen = ret;
+
+ mutex_unlock(&spi->lock);
return 0;
}
--
2.34.1
More information about the linux-mtd
mailing list