2024-03-05 18:25:06

by Mukesh Ojha

[permalink] [raw]
Subject: [PATCH] nvmem: qfprom: Add constraint read for some SoCs

Few SoCs starting from sm8450 where fuse region is
accessed using secure bus where it is not possible
to do incremental bytewise reading, while it is
possible to read 4 byte at a time.

Add required support in qfprom driver to support
reading fuse information on these SoCs.

Signed-off-by: Mukesh Ojha <[email protected]>
---
drivers/nvmem/qfprom.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 5 deletions(-)

diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index 116a39e804c7..8fce445f0320 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -68,6 +68,7 @@ struct qfprom_soc_data {
* @secclk: Clock supply.
* @vcc: Regulator supply.
* @soc_data: Data that for things that varies from SoC to SoC.
+ * @soc_cdata: Data that are relevant to convey SoC constraints.
*/
struct qfprom_priv {
void __iomem *qfpraw;
@@ -78,6 +79,7 @@ struct qfprom_priv {
struct clk *secclk;
struct regulator *vcc;
const struct qfprom_soc_data *soc_data;
+ const struct qfprom_soc_compatible_data *soc_cdata;
};

/**
@@ -99,10 +101,14 @@ struct qfprom_touched_values {
*
* @keepout: Array of keepout regions for this SoC.
* @nkeepout: Number of elements in the keepout array.
+ * @word_size: Should be given for SoC where it is not possible
+ * to do incremental reading or bytewise and while
+ * it is possible read 4 byte at a time.
*/
struct qfprom_soc_compatible_data {
const struct nvmem_keepout *keepout;
unsigned int nkeepout;
+ unsigned int word_size;
};

static const struct nvmem_keepout sc7180_qfprom_keepout[] = {
@@ -125,6 +131,10 @@ static const struct qfprom_soc_compatible_data sc7280_qfprom = {
.nkeepout = ARRAY_SIZE(sc7280_qfprom_keepout)
};

+static const struct qfprom_soc_compatible_data sm8450_qfprom = {
+ .word_size = 4,
+};
+
/**
* qfprom_disable_fuse_blowing() - Undo enabling of fuse blowing.
* @priv: Our driver data.
@@ -317,21 +327,55 @@ static int qfprom_reg_write(void *context, unsigned int reg, void *_val,
return ret;
}

+static int __qfprom_reg_constraint_read(void __iomem *base, unsigned int reg,
+ void *_val, size_t bytes,
+ unsigned int word_size)
+{
+ unsigned int i;
+ u8 *val = _val;
+ u32 read_val;
+ u8 *tmp;
+
+ for (i = 0; i < bytes; i++, reg++) {
+ if (i == 0 || reg % word_size == 0) {
+ read_val = readl(base + (reg & ~(word_size - 1)));
+ tmp = (u8 *)&read_val;
+ }
+
+ val[i] = tmp[reg & (word_size - 1)];
+ }
+
+ return 0;
+}
+
+static int __qfprom_reg_read(void __iomem *base, unsigned int reg, void *_val,
+ size_t bytes)
+{
+ u8 *val = _val;
+ int words = bytes;
+ int i = 0;
+
+ while (words--)
+ *val++ = readb(base + reg + i++);
+
+ return 0;
+}
+
static int qfprom_reg_read(void *context,
unsigned int reg, void *_val, size_t bytes)
{
struct qfprom_priv *priv = context;
- u8 *val = _val;
- int i = 0, words = bytes;
void __iomem *base = priv->qfpcorrected;

if (read_raw_data && priv->qfpraw)
base = priv->qfpraw;

- while (words--)
- *val++ = readb(base + reg + i++);
+ if (priv->soc_cdata && priv->soc_cdata->word_size == 4)
+ return __qfprom_reg_constraint_read(base, reg,
+ _val, bytes,
+ priv->soc_cdata->word_size);

- return 0;
+ return __qfprom_reg_read(base, reg, _val, bytes);
}

static void qfprom_runtime_disable(void *data)
@@ -390,6 +434,7 @@ static int qfprom_probe(struct platform_device *pdev)
econfig.nkeepout = soc_data->nkeepout;
}

+ priv->soc_cdata = soc_data;
/*
* If more than one region is provided then the OS has the ability
* to write.
@@ -447,6 +492,7 @@ static const struct of_device_id qfprom_of_match[] = {
{ .compatible = "qcom,qfprom",},
{ .compatible = "qcom,sc7180-qfprom", .data = &sc7180_qfprom},
{ .compatible = "qcom,sc7280-qfprom", .data = &sc7280_qfprom},
+ { .compatible = "qcom,sm8450-qfprom", .data = &sm8450_qfprom},
{/* sentinel */},
};
MODULE_DEVICE_TABLE(of, qfprom_of_match);
--
2.7.4