179 lines
5.8 KiB
Diff
179 lines
5.8 KiB
Diff
From 3a41ac28583128600bce37a94ba7716f55c51d23 Mon Sep 17 00:00:00 2001
|
|
From: Yicong Yang <yangyicong@hisilicon.com>
|
|
Date: Thu, 24 Sep 2020 20:24:27 +0800
|
|
Subject: [PATCH 31/39] spi: hisi-sfc-v3xx: factor out IO modes configuration
|
|
|
|
mainline inclusion
|
|
from mainline-v5.10-rc1
|
|
commit 2c8af6a59744b242a193118c799a45621476f8ed
|
|
category: feature
|
|
bugzilla: https://gitee.com/openeuler/kernel/issues/I8CSBP
|
|
CVE: NA
|
|
|
|
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2c8af6a59744b242a193118c799a45621476f8ed
|
|
|
|
----------------------------------------------------------------------------
|
|
|
|
Factor IO modes configuration out of hisi_sfc_v3xx_generic_exec_op()
|
|
using an IO modes lookup table. This will make the process a bit clearer
|
|
and reduce the cyclomatic complexity. Simplify the IO mode definition
|
|
macros a little bit as well.
|
|
|
|
Also add the .supports_op() method for the controller mem ops, in order
|
|
to avoid OOB access.
|
|
|
|
Acked-by: John Garry <john.garry@huawei.com>
|
|
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
|
|
Link: https://lore.kernel.org/r/1600950270-52536-2-git-send-email-yangyicong@hisilicon.com
|
|
Signed-off-by: Mark Brown <broonie@kernel.org>
|
|
Signed-off-by: YunYi Yang <yangyunyi2@huawei.com>
|
|
|
|
Conflicts:
|
|
drivers/spi/spi-hisi-sfc-v3xx.c
|
|
---
|
|
drivers/spi/spi-hisi-sfc-v3xx.c | 94 ++++++++++++++++++++-------------
|
|
1 file changed, 56 insertions(+), 38 deletions(-)
|
|
|
|
diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c
|
|
index 7b90ba2184ac..9203a7c06aaa 100644
|
|
--- a/drivers/spi/spi-hisi-sfc-v3xx.c
|
|
+++ b/drivers/spi/spi-hisi-sfc-v3xx.c
|
|
@@ -23,12 +23,6 @@
|
|
#define HISI_SFC_V3XX_INT_CLR (0x12c)
|
|
#define HISI_SFC_V3XX_INT_CLR_CLEAR (0xff)
|
|
#define HISI_SFC_V3XX_CMD_CFG (0x300)
|
|
-#define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17)
|
|
-#define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17)
|
|
-#define HISI_SFC_V3XX_CMD_CFG_FULL_DIO (3 << 17)
|
|
-#define HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT (5 << 17)
|
|
-#define HISI_SFC_V3XX_CMD_CFG_QUAD_IO (6 << 17)
|
|
-#define HISI_SFC_V3XX_CMD_CFG_FULL_QIO (7 << 17)
|
|
#define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9
|
|
#define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8)
|
|
#define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7)
|
|
@@ -40,6 +34,33 @@
|
|
#define HISI_SFC_V3XX_CMD_ADDR (0x30c)
|
|
#define HISI_SFC_V3XX_CMD_DATABUF0 (0x400)
|
|
|
|
+/* IO Mode definition in HISI_SFC_V3XX_CMD_CFG */
|
|
+#define HISI_SFC_V3XX_STD (0 << 17)
|
|
+#define HISI_SFC_V3XX_DIDO (1 << 17)
|
|
+#define HISI_SFC_V3XX_DIO (2 << 17)
|
|
+#define HISI_SFC_V3XX_FULL_DIO (3 << 17)
|
|
+#define HISI_SFC_V3XX_QIQO (5 << 17)
|
|
+#define HISI_SFC_V3XX_QIO (6 << 17)
|
|
+#define HISI_SFC_V3XX_FULL_QIO (7 << 17)
|
|
+
|
|
+/*
|
|
+ * The IO modes lookup table. hisi_sfc_v3xx_io_modes[(z - 1) / 2][y / 2][x / 2]
|
|
+ * stands for x-y-z mode, as described in SFDP terminology. -EIO indicates
|
|
+ * an invalid mode.
|
|
+ */
|
|
+static const int hisi_sfc_v3xx_io_modes[2][3][3] = {
|
|
+ {
|
|
+ { HISI_SFC_V3XX_DIDO, HISI_SFC_V3XX_DIDO, HISI_SFC_V3XX_DIDO },
|
|
+ { HISI_SFC_V3XX_DIO, HISI_SFC_V3XX_FULL_DIO, -EIO },
|
|
+ { -EIO, -EIO, -EIO },
|
|
+ },
|
|
+ {
|
|
+ { HISI_SFC_V3XX_QIQO, HISI_SFC_V3XX_QIQO, HISI_SFC_V3XX_QIQO },
|
|
+ { -EIO, -EIO, -EIO },
|
|
+ { HISI_SFC_V3XX_QIO, -EIO, HISI_SFC_V3XX_FULL_QIO },
|
|
+ },
|
|
+};
|
|
+
|
|
struct hisi_sfc_v3xx_host {
|
|
struct device *dev;
|
|
void __iomem *regbase;
|
|
@@ -79,6 +100,20 @@ static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem,
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * The controller only supports Standard SPI mode, Duall mode and
|
|
+ * Quad mode. Double sanitize the ops here to avoid OOB access.
|
|
+ */
|
|
+static bool hisi_sfc_v3xx_supports_op(struct spi_mem *mem,
|
|
+ const struct spi_mem_op *op)
|
|
+{
|
|
+ if (op->data.buswidth > 4 || op->dummy.buswidth > 4 ||
|
|
+ op->addr.buswidth > 4 || op->cmd.buswidth > 4)
|
|
+ return false;
|
|
+
|
|
+ return spi_mem_default_supports_op(mem, op);
|
|
+}
|
|
+
|
|
/*
|
|
* memcpy_{to,from}io doesn't gurantee 32b accesses - which we require for the
|
|
* DATABUF registers -so use __io{read,write}32_copy when possible. For
|
|
@@ -167,44 +202,26 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
|
|
const struct spi_mem_op *op,
|
|
u8 chip_select)
|
|
{
|
|
- int ret, len = op->data.nbytes;
|
|
+ int ret = 0, len = op->data.nbytes, buswidth_mode;
|
|
u32 int_stat, config = 0;
|
|
|
|
if (op->addr.nbytes)
|
|
config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK;
|
|
|
|
- switch (op->data.buswidth) {
|
|
- case 0 ... 1:
|
|
- break;
|
|
- case 2:
|
|
- if (op->addr.buswidth <= 1) {
|
|
- config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT;
|
|
- } else if (op->addr.buswidth == 2) {
|
|
- if (op->cmd.buswidth <= 1)
|
|
- config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IO;
|
|
- else if (op->cmd.buswidth == 2)
|
|
- config |= HISI_SFC_V3XX_CMD_CFG_FULL_DIO;
|
|
- else
|
|
- return -EIO;
|
|
- } else
|
|
- return -EIO;
|
|
- break;
|
|
- case 4:
|
|
- if (op->addr.buswidth <= 1) {
|
|
- config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT;
|
|
- } else if (op->addr.buswidth == 4) {
|
|
- if (op->cmd.buswidth <= 1)
|
|
- config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IO;
|
|
- else if (op->cmd.buswidth == 4)
|
|
- config |= HISI_SFC_V3XX_CMD_CFG_FULL_QIO;
|
|
- else
|
|
- return -EIO;
|
|
- } else
|
|
- return -EIO;
|
|
- break;
|
|
- default:
|
|
- return -EOPNOTSUPP;
|
|
+ if (op->data.buswidth == 0 || op->data.buswidth == 1) {
|
|
+ buswidth_mode = HISI_SFC_V3XX_STD;
|
|
+ } else {
|
|
+ int data_idx, addr_idx, cmd_idx;
|
|
+
|
|
+ data_idx = (op->data.buswidth - 1) / 2;
|
|
+ addr_idx = op->addr.buswidth / 2;
|
|
+ cmd_idx = op->cmd.buswidth / 2;
|
|
+ buswidth_mode =
|
|
+ hisi_sfc_v3xx_io_modes[data_idx][addr_idx][cmd_idx];
|
|
}
|
|
+ if (buswidth_mode < 0)
|
|
+ return buswidth_mode;
|
|
+ config |= buswidth_mode;
|
|
|
|
if (op->data.dir != SPI_MEM_NO_DATA) {
|
|
config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF;
|
|
@@ -268,6 +285,7 @@ static int hisi_sfc_v3xx_exec_op(struct spi_mem *mem,
|
|
|
|
static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = {
|
|
.adjust_op_size = hisi_sfc_v3xx_adjust_op_size,
|
|
+ .supports_op = hisi_sfc_v3xx_supports_op,
|
|
.exec_op = hisi_sfc_v3xx_exec_op,
|
|
};
|
|
|
|
--
|
|
2.27.0
|
|
|