Hi Greg,
Here are some nvmem patches bit more than usual for 6.3 which includes
- Add support to stm32 STM32MP15x OPTEE based nvmem provider
- Updated to qfprom bindings to include various Qualcomm SoCs.
- adding sl28vpd provider layout
- new helper eth_addr_add().
- few minor enhancements to core and providers drivers.
Can you please queue them up for 6.3.
changes since v1:
- rebased top of char-misc-next as dependency on few fixes in rc7.
- removed fixes tags as the commit ids are untracable.
- dropped layout patches for now.
thanks for you help,
srini
AngeloGioacchino Del Regno (1):
dt-bindings: nvmem: Fix qcom,qfprom compatibles enum ordering
Arnd Bergmann (1):
nvmem: stm32: fix OPTEE dependency
Johan Hovold (1):
nvmem: qcom-spmi-sdam: register at device init time
Konrad Dybcio (2):
dt-bindings: nvmem: Add compatible for SM8150
dt-bindings: nvmem: Add compatible for SM8250
Marijn Suijten (1):
dt-bindings: nvmem: Add compatible for MSM8976
Michael Walle (9):
net: add helper eth_addr_add()
of: base: add of_parse_phandle_with_optional_args()
of: property: make #.*-cells optional for simple props
of: property: add #nvmem-cell-cells property
nvmem: core: add an index parameter to the cell
nvmem: core: move struct nvmem_cell_info to nvmem-provider.h
nvmem: core: drop the removal of the cells in nvmem_add_cells()
nvmem: core: add nvmem_add_one_cell()
nvmem: core: use nvmem_add_one_cell() in nvmem_add_cells_from_of()
Patrick Delaunay (2):
nvmem: stm32: add OP-TEE support for STM32MP13x
nvmem: stm32: detect bsec pta presence for STM32MP15x
Randy Dunlap (1):
nvmem: rave-sp-eeprm: fix kernel-doc bad line warning
Richard Acayan (1):
dt-bindings: nvmem: qfprom: add sdm670 compatible
Robert Marko (1):
dt-bindings: nvmem: qfprom: add IPQ8074 compatible
Russell King (Oracle) (1):
nvmem: core: remove spurious white space
Samuel Holland (1):
nvmem: sunxi_sid: Drop the workaround on A64
.../bindings/nvmem/qcom,qfprom.yaml | 7 +-
drivers/nvmem/Kconfig | 10 +
drivers/nvmem/Makefile | 1 +
drivers/nvmem/core.c | 145 ++++-----
drivers/nvmem/imx-ocotp.c | 4 +-
drivers/nvmem/qcom-spmi-sdam.c | 13 +-
drivers/nvmem/rave-sp-eeprom.c | 2 +-
drivers/nvmem/stm32-bsec-optee-ta.c | 298 ++++++++++++++++++
drivers/nvmem/stm32-bsec-optee-ta.h | 80 +++++
drivers/nvmem/stm32-romem.c | 84 ++++-
drivers/nvmem/sunxi_sid.c | 8 +-
drivers/of/property.c | 6 +-
include/linux/etherdevice.h | 14 +
include/linux/nvmem-consumer.h | 10 +-
include/linux/nvmem-provider.h | 31 +-
include/linux/of.h | 25 ++
16 files changed, 626 insertions(+), 112 deletions(-)
create mode 100644 drivers/nvmem/stm32-bsec-optee-ta.c
create mode 100644 drivers/nvmem/stm32-bsec-optee-ta.h
--
2.25.1
From: Samuel Holland <[email protected]>
Now that the SRAM readout code is fixed by using 32-bit accesses, it
always returns the same values as register readout, so the A64 variant
no longer needs the workaround. This makes the D1 variant structure
redundant, so remove it.
Signed-off-by: Samuel Holland <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/sunxi_sid.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index 92dfe4cb10e3..a970f1741cc6 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -197,15 +197,9 @@ static const struct sunxi_sid_cfg sun8i_h3_cfg = {
.need_register_readout = true,
};
-static const struct sunxi_sid_cfg sun20i_d1_cfg = {
- .value_offset = 0x200,
- .size = 0x100,
-};
-
static const struct sunxi_sid_cfg sun50i_a64_cfg = {
.value_offset = 0x200,
.size = 0x100,
- .need_register_readout = true,
};
static const struct sunxi_sid_cfg sun50i_h6_cfg = {
@@ -218,7 +212,7 @@ static const struct of_device_id sunxi_sid_of_match[] = {
{ .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
{ .compatible = "allwinner,sun8i-a83t-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg },
- { .compatible = "allwinner,sun20i-d1-sid", .data = &sun20i_d1_cfg },
+ { .compatible = "allwinner,sun20i-d1-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun50i-h5-sid", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg },
--
2.25.1
From: AngeloGioacchino Del Regno <[email protected]>
Move qcom,msm8974-qfprom after qcom,msm8916-qfprom to respect
alphabetical ordering.
Signed-off-by: AngeloGioacchino Del Regno <[email protected]>
Reviewed-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index 8e89b15b535f..cc39514e8c84 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -19,8 +19,8 @@ properties:
- qcom,apq8064-qfprom
- qcom,apq8084-qfprom
- qcom,ipq8064-qfprom
- - qcom,msm8974-qfprom
- qcom,msm8916-qfprom
+ - qcom,msm8974-qfprom
- qcom,msm8996-qfprom
- qcom,msm8998-qfprom
- qcom,qcs404-qfprom
--
2.25.1
From: Marijn Suijten <[email protected]>
Document generic QFPROM compatibility on MSM8976.
Signed-off-by: Marijn Suijten <[email protected]>
Signed-off-by: AngeloGioacchino Del Regno <[email protected]>
Reviewed-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index cc39514e8c84..48cfec0c9ece 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -21,6 +21,7 @@ properties:
- qcom,ipq8064-qfprom
- qcom,msm8916-qfprom
- qcom,msm8974-qfprom
+ - qcom,msm8976-qfprom
- qcom,msm8996-qfprom
- qcom,msm8998-qfprom
- qcom,qcs404-qfprom
--
2.25.1
From: Richard Acayan <[email protected]>
There is some configuration in SDM670's QFPROM. Add the compatible for
it.
Signed-off-by: Richard Acayan <[email protected]>
Reviewed-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index 48cfec0c9ece..b7811bbb0e71 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -28,6 +28,7 @@ properties:
- qcom,sc7180-qfprom
- qcom,sc7280-qfprom
- qcom,sdm630-qfprom
+ - qcom,sdm670-qfprom
- qcom,sdm845-qfprom
- qcom,sm6115-qfprom
- const: qcom,qfprom
--
2.25.1
From: Konrad Dybcio <[email protected]>
Docuemnt the QFPROM on SM8150.
Signed-off-by: Konrad Dybcio <[email protected]>
Acked-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index b7811bbb0e71..a248033026b1 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -31,6 +31,7 @@ properties:
- qcom,sdm670-qfprom
- qcom,sdm845-qfprom
- qcom,sm6115-qfprom
+ - qcom,sm8150-qfprom
- const: qcom,qfprom
reg:
--
2.25.1
From: Konrad Dybcio <[email protected]>
Docuemnt the QFPROM on SM8250.
Signed-off-by: Konrad Dybcio <[email protected]>
Acked-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index a248033026b1..9ddf3cef9e84 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -32,6 +32,7 @@ properties:
- qcom,sdm845-qfprom
- qcom,sm6115-qfprom
- qcom,sm8150-qfprom
+ - qcom,sm8250-qfprom
- const: qcom,qfprom
reg:
--
2.25.1
From: "Russell King (Oracle)" <[email protected]>
Remove a spurious white space in for the ida_alloc() call.
Signed-off-by: Russell King (Oracle) <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 34ee9d36ee7b..233c6c275031 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -764,7 +764,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (!nvmem)
return ERR_PTR(-ENOMEM);
- rval = ida_alloc(&nvmem_ida, GFP_KERNEL);
+ rval = ida_alloc(&nvmem_ida, GFP_KERNEL);
if (rval < 0) {
kfree(nvmem);
return ERR_PTR(rval);
--
2.25.1
From: Michael Walle <[email protected]>
Add a helper to add an offset to a ethernet address. This comes in handy
if you have a base ethernet address for multiple interfaces.
Signed-off-by: Michael Walle <[email protected]>
Reviewed-by: Andrew Lunn <[email protected]>
Acked-by: Jakub Kicinski <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
include/linux/etherdevice.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index a541f0c4f146..224645f17c33 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -507,6 +507,20 @@ static inline void eth_addr_inc(u8 *addr)
u64_to_ether_addr(u, addr);
}
+/**
+ * eth_addr_add() - Add (or subtract) an offset to/from the given MAC address.
+ *
+ * @offset: Offset to add.
+ * @addr: Pointer to a six-byte array containing Ethernet address to increment.
+ */
+static inline void eth_addr_add(u8 *addr, long offset)
+{
+ u64 u = ether_addr_to_u64(addr);
+
+ u += offset;
+ u64_to_ether_addr(u, addr);
+}
+
/**
* is_etherdev_addr - Tell if given Ethernet address belongs to the device.
* @dev: Pointer to a device structure
--
2.25.1
From: Michael Walle <[email protected]>
Add a new variant of the of_parse_phandle_with_args() which treats the
cells name as optional. If it's missing, it is assumed that the phandle
has no arguments.
Up until now, a nvmem node didn't have any arguments, so all the device
trees haven't any '#*-cells' property. But there is a need for an
additional argument for the phandle, for which we need a '#*-cells'
property. Therefore, we need to support nvmem nodes with and without
this property.
Signed-off-by: Michael Walle <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
include/linux/of.h | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/include/linux/of.h b/include/linux/of.h
index 8b9f94386dc3..98c252d2d851 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -1008,6 +1008,31 @@ static inline int of_parse_phandle_with_fixed_args(const struct device_node *np,
index, out_args);
}
+/**
+ * of_parse_phandle_with_optional_args() - Find a node pointed by phandle in a list
+ * @np: pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies phandles' arguments count
+ * @index: index of a phandle to parse out
+ * @out_args: optional pointer to output arguments structure (will be filled)
+ *
+ * Same as of_parse_phandle_with_args() except that if the cells_name property
+ * is not found, cell_count of 0 is assumed.
+ *
+ * This is used to useful, if you have a phandle which didn't have arguments
+ * before and thus doesn't have a '#*-cells' property but is now migrated to
+ * having arguments while retaining backwards compatibility.
+ */
+static inline int of_parse_phandle_with_optional_args(const struct device_node *np,
+ const char *list_name,
+ const char *cells_name,
+ int index,
+ struct of_phandle_args *out_args)
+{
+ return __of_parse_phandle_with_args(np, list_name, cells_name,
+ 0, index, out_args);
+}
+
/**
* of_property_count_u8_elems - Count the number of u8 elements in a property
*
--
2.25.1
From: Michael Walle <[email protected]>
Bindings describe the new '#nvmem-cell-cells' property. Now that the
arguments count property is optional, we just add this property to the
nvmem-cells.
Signed-off-by: Michael Walle <[email protected]>
Tested-by: Miquel Raynal <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/of/property.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 989e692e0319..95b838185b2f 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1307,7 +1307,7 @@ DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-cells")
DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells")
DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells")
DEFINE_SIMPLE_PROP(extcon, "extcon", NULL)
-DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", NULL)
+DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", "#nvmem-cell-cells")
DEFINE_SIMPLE_PROP(phys, "phys", "#phy-cells")
DEFINE_SIMPLE_PROP(wakeup_parent, "wakeup-parent", NULL)
DEFINE_SIMPLE_PROP(pinctrl0, "pinctrl-0", NULL)
--
2.25.1
From: Michael Walle <[email protected]>
Sometimes, future bindings for phandles will get additional arguments.
Thus the target node of the phandle will need a new #.*-cells property.
To be backwards compatible, this needs to be optional.
Prepare the DEFINE_SIMPLE_PROPS() to handle the cells name as optional.
Signed-off-by: Michael Walle <[email protected]>
Tested-by: Miquel Raynal <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/of/property.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/of/property.c b/drivers/of/property.c
index 134cfc980b70..989e692e0319 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1202,8 +1202,8 @@ static struct device_node *parse_prop_cells(struct device_node *np,
if (strcmp(prop_name, list_name))
return NULL;
- if (of_parse_phandle_with_args(np, list_name, cells_name, index,
- &sup_args))
+ if (__of_parse_phandle_with_args(np, list_name, cells_name, 0, index,
+ &sup_args))
return NULL;
return sup_args.np;
--
2.25.1
From: Michael Walle <[email protected]>
Sometimes a cell can represend multiple values. For example, a base
ethernet address stored in the NVMEM can be expanded into multiple
discreet ones by adding an offset.
For this use case, introduce an index parameter which is then used to
distiguish between values. This parameter will then be passed to the
post process hook which can then use it to create different values
during reading.
At the moment, there is only support for the device tree path. You can
add the index to the phandle, e.g.
&net {
nvmem-cells = <&base_mac_address 2>;
nvmem-cell-names = "mac-address";
};
&nvmem_provider {
base_mac_address: base-mac-address@0 {
#nvmem-cell-cells = <1>;
reg = <0 6>;
};
};
Signed-off-by: Michael Walle <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/core.c | 37 ++++++++++++++++++++++++----------
drivers/nvmem/imx-ocotp.c | 4 ++--
include/linux/nvmem-provider.h | 4 ++--
3 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 233c6c275031..30567dd51fba 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -60,6 +60,7 @@ struct nvmem_cell_entry {
struct nvmem_cell {
struct nvmem_cell_entry *entry;
const char *id;
+ int index;
};
static DEFINE_MUTEX(nvmem_mutex);
@@ -1122,7 +1123,8 @@ struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
}
EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
-static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, const char *id)
+static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
+ const char *id, int index)
{
struct nvmem_cell *cell;
const char *name = NULL;
@@ -1141,6 +1143,7 @@ static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, cons
cell->id = name;
cell->entry = entry;
+ cell->index = index;
return cell;
}
@@ -1179,7 +1182,7 @@ nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
__nvmem_device_put(nvmem);
cell = ERR_PTR(-ENOENT);
} else {
- cell = nvmem_create_cell(cell_entry, con_id);
+ cell = nvmem_create_cell(cell_entry, con_id, 0);
if (IS_ERR(cell))
__nvmem_device_put(nvmem);
}
@@ -1227,15 +1230,27 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
struct nvmem_device *nvmem;
struct nvmem_cell_entry *cell_entry;
struct nvmem_cell *cell;
+ struct of_phandle_args cell_spec;
int index = 0;
+ int cell_index = 0;
+ int ret;
/* if cell name exists, find index to the name */
if (id)
index = of_property_match_string(np, "nvmem-cell-names", id);
- cell_np = of_parse_phandle(np, "nvmem-cells", index);
- if (!cell_np)
- return ERR_PTR(-ENOENT);
+ ret = of_parse_phandle_with_optional_args(np, "nvmem-cells",
+ "#nvmem-cell-cells",
+ index, &cell_spec);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (cell_spec.args_count > 1)
+ return ERR_PTR(-EINVAL);
+
+ cell_np = cell_spec.np;
+ if (cell_spec.args_count)
+ cell_index = cell_spec.args[0];
nvmem_np = of_get_parent(cell_np);
if (!nvmem_np) {
@@ -1257,7 +1272,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
return ERR_PTR(-ENOENT);
}
- cell = nvmem_create_cell(cell_entry, id);
+ cell = nvmem_create_cell(cell_entry, id, cell_index);
if (IS_ERR(cell))
__nvmem_device_put(nvmem);
@@ -1410,8 +1425,8 @@ static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void
}
static int __nvmem_cell_read(struct nvmem_device *nvmem,
- struct nvmem_cell_entry *cell,
- void *buf, size_t *len, const char *id)
+ struct nvmem_cell_entry *cell,
+ void *buf, size_t *len, const char *id, int index)
{
int rc;
@@ -1425,7 +1440,7 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem,
nvmem_shift_read_buffer_in_place(cell, buf);
if (nvmem->cell_post_process) {
- rc = nvmem->cell_post_process(nvmem->priv, id,
+ rc = nvmem->cell_post_process(nvmem->priv, id, index,
cell->offset, buf, cell->bytes);
if (rc)
return rc;
@@ -1460,7 +1475,7 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
if (!buf)
return ERR_PTR(-ENOMEM);
- rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id);
+ rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id, cell->index);
if (rc) {
kfree(buf);
return ERR_PTR(rc);
@@ -1773,7 +1788,7 @@ ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
if (rc)
return rc;
- rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL);
+ rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0);
if (rc)
return rc;
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 14284e866f26..e9b52ecb3f72 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -222,8 +222,8 @@ static int imx_ocotp_read(void *context, unsigned int offset,
return ret;
}
-static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset,
- void *data, size_t bytes)
+static int imx_ocotp_cell_pp(void *context, const char *id, int index,
+ unsigned int offset, void *data, size_t bytes)
{
struct ocotp_priv *priv = context;
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index bb15c9234e21..55181d837969 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -20,8 +20,8 @@ typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset,
typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
void *val, size_t bytes);
/* used for vendor specific post processing of cell data */
-typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, unsigned int offset,
- void *buf, size_t bytes);
+typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, int index,
+ unsigned int offset, void *buf, size_t bytes);
enum nvmem_type {
NVMEM_TYPE_UNKNOWN = 0,
--
2.25.1
From: Michael Walle <[email protected]>
struct nvmem_cell_info is used to describe a cell. Thus this should
really be in the nvmem-provider's header. There are two (unused) nvmem
access methods which use the nvmem_cell_info to describe the cell to be
accesses. One can argue, that they will create a cell before accessing,
thus they are both a provider and a consumer.
struct nvmem_cell_info will get used more and more by nvmem-providers,
don't force them to also include the consumer header, although they are
not.
Signed-off-by: Michael Walle <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
include/linux/nvmem-consumer.h | 10 +---------
include/linux/nvmem-provider.h | 19 ++++++++++++++++++-
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index 980f9c9ac0bc..1f62f7ba71ca 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -18,15 +18,7 @@ struct device_node;
/* consumer cookie */
struct nvmem_cell;
struct nvmem_device;
-
-struct nvmem_cell_info {
- const char *name;
- unsigned int offset;
- unsigned int bytes;
- unsigned int bit_offset;
- unsigned int nbits;
- struct device_node *np;
-};
+struct nvmem_cell_info;
/**
* struct nvmem_cell_lookup - cell lookup entry
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 55181d837969..a953a3a59535 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -14,7 +14,6 @@
#include <linux/gpio/consumer.h>
struct nvmem_device;
-struct nvmem_cell_info;
typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset,
void *val, size_t bytes);
typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
@@ -47,6 +46,24 @@ struct nvmem_keepout {
unsigned char value;
};
+/**
+ * struct nvmem_cell_info - NVMEM cell description
+ * @name: Name.
+ * @offset: Offset within the NVMEM device.
+ * @bytes: Length of the cell.
+ * @bit_offset: Bit offset if cell is smaller than a byte.
+ * @nbits: Number of bits.
+ * @np: Optional device_node pointer.
+ */
+struct nvmem_cell_info {
+ const char *name;
+ unsigned int offset;
+ unsigned int bytes;
+ unsigned int bit_offset;
+ unsigned int nbits;
+ struct device_node *np;
+};
+
/**
* struct nvmem_config - NVMEM device configuration
*
--
2.25.1
From: Michael Walle <[email protected]>
If nvmem_add_cells() fails, the whole nvmem_register() will fail
and the cells will then be removed anyway. This is a preparation
to introduce a nvmem_add_one_cell() which can then be used by
nvmem_add_cells().
This is then the same to what nvmem_add_cells_from_table() and
nvmem_add_cells_from_of() do.
Signed-off-by: Michael Walle <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/core.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 30567dd51fba..98ae70695f36 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -515,7 +515,7 @@ static int nvmem_add_cells(struct nvmem_device *nvmem,
int ncells)
{
struct nvmem_cell_entry **cells;
- int i, rval;
+ int i, rval = 0;
cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL);
if (!cells)
@@ -525,28 +525,22 @@ static int nvmem_add_cells(struct nvmem_device *nvmem,
cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
if (!cells[i]) {
rval = -ENOMEM;
- goto err;
+ goto out;
}
rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]);
if (rval) {
kfree(cells[i]);
- goto err;
+ goto out;
}
nvmem_cell_entry_add(cells[i]);
}
+out:
/* remove tmp array */
kfree(cells);
- return 0;
-err:
- while (i--)
- nvmem_cell_entry_drop(cells[i]);
-
- kfree(cells);
-
return rval;
}
--
2.25.1
From: Michael Walle <[email protected]>
Convert nvmem_add_cells_from_of() to use the new nvmem_add_one_cell().
This will remove duplicate code and it will make it possible to add a
hook to a nvmem layout in between, which can change fields before the
cell is finally added.
Signed-off-by: Michael Walle <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/core.c | 45 ++++++++++++++------------------------------
1 file changed, 14 insertions(+), 31 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 58f8e33e7a8c..174ef3574e07 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -688,15 +688,14 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
{
- struct device_node *parent, *child;
struct device *dev = &nvmem->dev;
- struct nvmem_cell_entry *cell;
+ struct device_node *child;
const __be32 *addr;
- int len;
+ int len, ret;
- parent = dev->of_node;
+ for_each_child_of_node(dev->of_node, child) {
+ struct nvmem_cell_info info = {0};
- for_each_child_of_node(parent, child) {
addr = of_get_property(child, "reg", &len);
if (!addr)
continue;
@@ -706,40 +705,24 @@ static int nvmem_add_cells_from_of(struct nvmem_device *nvmem)
return -EINVAL;
}
- cell = kzalloc(sizeof(*cell), GFP_KERNEL);
- if (!cell) {
- of_node_put(child);
- return -ENOMEM;
- }
-
- cell->nvmem = nvmem;
- cell->offset = be32_to_cpup(addr++);
- cell->bytes = be32_to_cpup(addr);
- cell->name = kasprintf(GFP_KERNEL, "%pOFn", child);
+ info.offset = be32_to_cpup(addr++);
+ info.bytes = be32_to_cpup(addr);
+ info.name = kasprintf(GFP_KERNEL, "%pOFn", child);
addr = of_get_property(child, "bits", &len);
if (addr && len == (2 * sizeof(u32))) {
- cell->bit_offset = be32_to_cpup(addr++);
- cell->nbits = be32_to_cpup(addr);
+ info.bit_offset = be32_to_cpup(addr++);
+ info.nbits = be32_to_cpup(addr);
}
- if (cell->nbits)
- cell->bytes = DIV_ROUND_UP(
- cell->nbits + cell->bit_offset,
- BITS_PER_BYTE);
+ info.np = of_node_get(child);
- if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
- dev_err(dev, "cell %s unaligned to nvmem stride %d\n",
- cell->name, nvmem->stride);
- /* Cells already added will be freed later. */
- kfree_const(cell->name);
- kfree(cell);
+ ret = nvmem_add_one_cell(nvmem, &info);
+ kfree(info.name);
+ if (ret) {
of_node_put(child);
- return -EINVAL;
+ return ret;
}
-
- cell->np = of_node_get(child);
- nvmem_cell_entry_add(cell);
}
return 0;
--
2.25.1
From: Michael Walle <[email protected]>
Add a new function to add exactly one cell. This will be used by the
nvmem layout drivers to add custom cells. In contrast to the
nvmem_add_cells(), this has the advantage that we don't have to assemble
a list of cells on runtime.
Signed-off-by: Michael Walle <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/core.c | 59 ++++++++++++++++++++--------------
include/linux/nvmem-provider.h | 8 +++++
2 files changed, 43 insertions(+), 24 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 98ae70695f36..58f8e33e7a8c 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -501,6 +501,36 @@ static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem,
return 0;
}
+/**
+ * nvmem_add_one_cell() - Add one cell information to an nvmem device
+ *
+ * @nvmem: nvmem device to add cells to.
+ * @info: nvmem cell info to add to the device
+ *
+ * Return: 0 or negative error code on failure.
+ */
+int nvmem_add_one_cell(struct nvmem_device *nvmem,
+ const struct nvmem_cell_info *info)
+{
+ struct nvmem_cell_entry *cell;
+ int rval;
+
+ cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+ if (!cell)
+ return -ENOMEM;
+
+ rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell);
+ if (rval) {
+ kfree(cell);
+ return rval;
+ }
+
+ nvmem_cell_entry_add(cell);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_add_one_cell);
+
/**
* nvmem_add_cells() - Add cell information to an nvmem device
*
@@ -514,34 +544,15 @@ static int nvmem_add_cells(struct nvmem_device *nvmem,
const struct nvmem_cell_info *info,
int ncells)
{
- struct nvmem_cell_entry **cells;
- int i, rval = 0;
-
- cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL);
- if (!cells)
- return -ENOMEM;
+ int i, rval;
for (i = 0; i < ncells; i++) {
- cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
- if (!cells[i]) {
- rval = -ENOMEM;
- goto out;
- }
-
- rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]);
- if (rval) {
- kfree(cells[i]);
- goto out;
- }
-
- nvmem_cell_entry_add(cells[i]);
+ rval = nvmem_add_one_cell(nvmem, &info[i]);
+ if (rval)
+ return rval;
}
-out:
- /* remove tmp array */
- kfree(cells);
-
- return rval;
+ return 0;
}
/**
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index a953a3a59535..0262b86194eb 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -153,6 +153,9 @@ struct nvmem_device *devm_nvmem_register(struct device *dev,
void nvmem_add_cell_table(struct nvmem_cell_table *table);
void nvmem_del_cell_table(struct nvmem_cell_table *table);
+int nvmem_add_one_cell(struct nvmem_device *nvmem,
+ const struct nvmem_cell_info *info);
+
#else
static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c)
@@ -170,6 +173,11 @@ devm_nvmem_register(struct device *dev, const struct nvmem_config *c)
static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {}
static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {}
+static inline int nvmem_add_one_cell(struct nvmem_device *nvmem,
+ const struct nvmem_cell_info *info)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_NVMEM */
#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
--
2.25.1
From: Patrick Delaunay <[email protected]>
For boot with OP-TEE on STM32MP13, the communication with the secure
world no more use STMicroelectronics SMC but communication with the
STM32MP BSEC TA, for data access (read/write) or lock operation:
- all the request are sent to OP-TEE trusted application,
- for upper OTP with ECC protection and with word programming only
each OTP are permanently locked when programmed to avoid ECC error
on the second write operation
Signed-off-by: Patrick Delaunay <[email protected]>
Reviewed-by: Etienne Carriere <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/Kconfig | 11 +
drivers/nvmem/Makefile | 1 +
drivers/nvmem/stm32-bsec-optee-ta.c | 298 ++++++++++++++++++++++++++++
drivers/nvmem/stm32-bsec-optee-ta.h | 80 ++++++++
drivers/nvmem/stm32-romem.c | 54 ++++-
5 files changed, 441 insertions(+), 3 deletions(-)
create mode 100644 drivers/nvmem/stm32-bsec-optee-ta.c
create mode 100644 drivers/nvmem/stm32-bsec-optee-ta.h
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 755f551426b5..4d262f69a073 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -290,9 +290,20 @@ config NVMEM_SPRD_EFUSE
This driver can also be built as a module. If so, the module
will be called nvmem-sprd-efuse.
+config NVMEM_STM32_BSEC_OPTEE_TA
+ bool "STM32MP BSEC OP-TEE TA support for nvmem-stm32-romem driver"
+ depends on OPTEE
+ help
+ Say y here to enable the accesses to STM32MP SoC OTPs by the OP-TEE
+ trusted application STM32MP BSEC.
+
+ This library is a used by stm32-romem driver or included in the module
+ called nvmem-stm32-romem.
+
config NVMEM_STM32_ROMEM
tristate "STMicroelectronics STM32 factory-programmed memory support"
depends on ARCH_STM32 || COMPILE_TEST
+ imply NVMEM_STM32_BSEC_OPTEE_TA
help
Say y here to enable read-only access for STMicroelectronics STM32
factory-programmed memory area.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index fa80fe17e567..6a1efffa88f0 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o
nvmem_sprd_efuse-y := sprd-efuse.o
obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o
nvmem_stm32_romem-y := stm32-romem.o
+nvmem_stm32_romem-$(CONFIG_NVMEM_STM32_BSEC_OPTEE_TA) += stm32-bsec-optee-ta.o
obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o
nvmem_sunplus_ocotp-y := sunplus-ocotp.o
obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
diff --git a/drivers/nvmem/stm32-bsec-optee-ta.c b/drivers/nvmem/stm32-bsec-optee-ta.c
new file mode 100644
index 000000000000..f89ce791dd12
--- /dev/null
+++ b/drivers/nvmem/stm32-bsec-optee-ta.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * OP-TEE STM32MP BSEC PTA interface, used by STM32 ROMEM driver
+ *
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#include <linux/tee_drv.h>
+
+#include "stm32-bsec-optee-ta.h"
+
+/*
+ * Read OTP memory
+ *
+ * [in] value[0].a OTP start offset in byte
+ * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock)
+ * [out] memref[1].buffer Output buffer to store read values
+ * [out] memref[1].size Size of OTP to be read
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
+ */
+#define PTA_BSEC_READ_MEM 0x0
+
+/*
+ * Write OTP memory
+ *
+ * [in] value[0].a OTP start offset in byte
+ * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock)
+ * [in] memref[1].buffer Input buffer to read values
+ * [in] memref[1].size Size of OTP to be written
+ *
+ * Return codes:
+ * TEE_SUCCESS - Invoke command success
+ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
+ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller
+ */
+#define PTA_BSEC_WRITE_MEM 0x1
+
+/* value of PTA_BSEC access type = value[in] b */
+#define SHADOW_ACCESS 0
+#define FUSE_ACCESS 1
+#define LOCK_ACCESS 2
+
+/* Bitfield definition for LOCK status */
+#define LOCK_PERM BIT(30)
+
+/* OP-TEE STM32MP BSEC TA UUID */
+static const uuid_t stm32mp_bsec_ta_uuid =
+ UUID_INIT(0x94cf71ad, 0x80e6, 0x40b5,
+ 0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03);
+
+/*
+ * Check whether this driver supports the BSEC TA in the TEE instance
+ * represented by the params (ver/data) to this function.
+ */
+static int stm32_bsec_optee_ta_match(struct tee_ioctl_version_data *ver,
+ const void *data)
+{
+ /* Currently this driver only supports GP compliant, OP-TEE based TA */
+ if ((ver->impl_id == TEE_IMPL_ID_OPTEE) &&
+ (ver->gen_caps & TEE_GEN_CAP_GP))
+ return 1;
+ else
+ return 0;
+}
+
+/* Open a session to OP-TEE for STM32MP BSEC TA */
+static int stm32_bsec_ta_open_session(struct tee_context *ctx, u32 *id)
+{
+ struct tee_ioctl_open_session_arg sess_arg;
+ int rc;
+
+ memset(&sess_arg, 0, sizeof(sess_arg));
+ export_uuid(sess_arg.uuid, &stm32mp_bsec_ta_uuid);
+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+ sess_arg.num_params = 0;
+
+ rc = tee_client_open_session(ctx, &sess_arg, NULL);
+ if ((rc < 0) || (sess_arg.ret != 0)) {
+ pr_err("%s: tee_client_open_session failed err:%#x, ret:%#x\n",
+ __func__, sess_arg.ret, rc);
+ if (!rc)
+ rc = -EINVAL;
+ } else {
+ *id = sess_arg.session;
+ }
+
+ return rc;
+}
+
+/* close a session to OP-TEE for STM32MP BSEC TA */
+static void stm32_bsec_ta_close_session(void *ctx, u32 id)
+{
+ tee_client_close_session(ctx, id);
+}
+
+/* stm32_bsec_optee_ta_open() - initialize the STM32MP BSEC TA */
+int stm32_bsec_optee_ta_open(struct tee_context **ctx)
+{
+ struct tee_context *tee_ctx;
+ u32 session_id;
+ int rc;
+
+ /* Open context with TEE driver */
+ tee_ctx = tee_client_open_context(NULL, stm32_bsec_optee_ta_match, NULL, NULL);
+ if (IS_ERR(tee_ctx)) {
+ rc = PTR_ERR(tee_ctx);
+ if (rc == -ENOENT)
+ return -EPROBE_DEFER;
+ pr_err("%s: tee_client_open_context failed (%d)\n", __func__, rc);
+
+ return rc;
+ }
+
+ /* Check STM32MP BSEC TA presence */
+ rc = stm32_bsec_ta_open_session(tee_ctx, &session_id);
+ if (rc) {
+ tee_client_close_context(tee_ctx);
+ return rc;
+ }
+
+ stm32_bsec_ta_close_session(tee_ctx, session_id);
+
+ *ctx = tee_ctx;
+
+ return 0;
+}
+
+/* stm32_bsec_optee_ta_open() - release the PTA STM32MP BSEC TA */
+void stm32_bsec_optee_ta_close(void *ctx)
+{
+ tee_client_close_context(ctx);
+}
+
+/* stm32_bsec_optee_ta_read() - nvmem read access using PTA client driver */
+int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset,
+ void *buf, size_t bytes)
+{
+ struct tee_shm *shm;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_param param[2];
+ u8 *shm_buf;
+ u32 start, num_bytes;
+ int ret;
+ u32 session_id;
+
+ ret = stm32_bsec_ta_open_session(ctx, &session_id);
+ if (ret)
+ return ret;
+
+ memset(&arg, 0, sizeof(arg));
+ memset(¶m, 0, sizeof(param));
+
+ arg.func = PTA_BSEC_READ_MEM;
+ arg.session = session_id;
+ arg.num_params = 2;
+
+ /* align access on 32bits */
+ start = ALIGN_DOWN(offset, 4);
+ num_bytes = round_up(offset + bytes - start, 4);
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = start;
+ param[0].u.value.b = SHADOW_ACCESS;
+
+ shm = tee_shm_alloc_kernel_buf(ctx, num_bytes);
+ if (IS_ERR(shm)) {
+ ret = PTR_ERR(shm);
+ goto out_tee_session;
+ }
+
+ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT;
+ param[1].u.memref.shm = shm;
+ param[1].u.memref.size = num_bytes;
+
+ ret = tee_client_invoke_func(ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n",
+ arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+ if (!ret) {
+ shm_buf = tee_shm_get_va(shm, 0);
+ if (IS_ERR(shm_buf)) {
+ ret = PTR_ERR(shm_buf);
+ pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
+ } else {
+ /* read data from 32 bits aligned buffer */
+ memcpy(buf, &shm_buf[offset % 4], bytes);
+ }
+ }
+
+ tee_shm_free(shm);
+
+out_tee_session:
+ stm32_bsec_ta_close_session(ctx, session_id);
+
+ return ret;
+}
+
+/* stm32_bsec_optee_ta_write() - nvmem write access using PTA client driver */
+int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower,
+ unsigned int offset, void *buf, size_t bytes)
+{ struct tee_shm *shm;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_param param[2];
+ u8 *shm_buf;
+ int ret;
+ u32 session_id;
+
+ ret = stm32_bsec_ta_open_session(ctx, &session_id);
+ if (ret)
+ return ret;
+
+ /* Allow only writing complete 32-bits aligned words */
+ if ((bytes % 4) || (offset % 4))
+ return -EINVAL;
+
+ memset(&arg, 0, sizeof(arg));
+ memset(¶m, 0, sizeof(param));
+
+ arg.func = PTA_BSEC_WRITE_MEM;
+ arg.session = session_id;
+ arg.num_params = 2;
+
+ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ param[0].u.value.a = offset;
+ param[0].u.value.b = FUSE_ACCESS;
+
+ shm = tee_shm_alloc_kernel_buf(ctx, bytes);
+ if (IS_ERR(shm)) {
+ ret = PTR_ERR(shm);
+ goto out_tee_session;
+ }
+
+ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ param[1].u.memref.shm = shm;
+ param[1].u.memref.size = bytes;
+
+ shm_buf = tee_shm_get_va(shm, 0);
+ if (IS_ERR(shm_buf)) {
+ ret = PTR_ERR(shm_buf);
+ pr_err("tee_shm_get_va failed for transmit (%d)\n", ret);
+ tee_shm_free(shm);
+
+ goto out_tee_session;
+ }
+
+ memcpy(shm_buf, buf, bytes);
+
+ ret = tee_client_invoke_func(ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+ pr_debug("Write OTPs %d to %zu, ret=%d\n", offset / 4, (offset + bytes) / 4, ret);
+
+ /* Lock the upper OTPs with ECC protection, word programming only */
+ if (!ret && ((offset + bytes) >= (lower * 4))) {
+ u32 start, nb_lock;
+ u32 *lock = (u32 *)shm_buf;
+ int i;
+
+ /*
+ * don't lock the lower OTPs, no ECC protection and incremental
+ * bit programming, a second write is allowed
+ */
+ start = max_t(u32, offset, lower * 4);
+ nb_lock = (offset + bytes - start) / 4;
+
+ param[0].u.value.a = start;
+ param[0].u.value.b = LOCK_ACCESS;
+ param[1].u.memref.size = nb_lock * 4;
+
+ for (i = 0; i < nb_lock; i++)
+ lock[i] = LOCK_PERM;
+
+ ret = tee_client_invoke_func(ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+ pr_debug("Lock upper OTPs %d to %d, ret=%d\n",
+ start / 4, start / 4 + nb_lock, ret);
+ }
+
+ tee_shm_free(shm);
+
+out_tee_session:
+ stm32_bsec_ta_close_session(ctx, session_id);
+
+ return ret;
+}
diff --git a/drivers/nvmem/stm32-bsec-optee-ta.h b/drivers/nvmem/stm32-bsec-optee-ta.h
new file mode 100644
index 000000000000..3966a0535179
--- /dev/null
+++ b/drivers/nvmem/stm32-bsec-optee-ta.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * OP-TEE STM32MP BSEC PTA interface, used by STM32 ROMEM driver
+ *
+ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
+ */
+
+#if IS_ENABLED(CONFIG_NVMEM_STM32_BSEC_OPTEE_TA)
+/**
+ * stm32_bsec_optee_ta_open() - initialize the STM32 BSEC TA
+ * @ctx: the OP-TEE context on success
+ *
+ * Return:
+ * On success, 0. On failure, -errno.
+ */
+int stm32_bsec_optee_ta_open(struct tee_context **ctx);
+
+/**
+ * stm32_bsec_optee_ta_close() - release the STM32 BSEC TA
+ * @ctx: the OP-TEE context
+ *
+ * This function used to clean the OP-TEE resources initialized in
+ * stm32_bsec_optee_ta_open(); it can be used as callback to
+ * devm_add_action_or_reset()
+ */
+void stm32_bsec_optee_ta_close(void *ctx);
+
+/**
+ * stm32_bsec_optee_ta_read() - nvmem read access using TA client driver
+ * @ctx: the OP-TEE context provided by stm32_bsec_optee_ta_open
+ * @offset: nvmem offset
+ * @buf: buffer to fill with nvem values
+ * @bytes: number of bytes to read
+ *
+ * Return:
+ * On success, 0. On failure, -errno.
+ */
+int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset,
+ void *buf, size_t bytes);
+
+/**
+ * stm32_bsec_optee_ta_write() - nvmem write access using TA client driver
+ * @ctx: the OP-TEE context provided by stm32_bsec_optee_ta_open
+ * @lower: number of lower OTP, not protected by ECC
+ * @offset: nvmem offset
+ * @buf: buffer with nvem values
+ * @bytes: number of bytes to write
+ *
+ * Return:
+ * On success, 0. On failure, -errno.
+ */
+int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower,
+ unsigned int offset, void *buf, size_t bytes);
+
+#else
+
+static inline int stm32_bsec_optee_ta_open(struct tee_context **ctx)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void stm32_bsec_optee_ta_close(void *ctx)
+{
+}
+
+static inline int stm32_bsec_optee_ta_read(struct tee_context *ctx,
+ unsigned int offset, void *buf,
+ size_t bytes)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int stm32_bsec_optee_ta_write(struct tee_context *ctx,
+ unsigned int lower,
+ unsigned int offset, void *buf,
+ size_t bytes)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_NVMEM_STM32_BSEC_OPTEE_TA */
diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index d1d03c2ad081..978a63edf297 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -11,6 +11,9 @@
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/of_device.h>
+#include <linux/tee_drv.h>
+
+#include "stm32-bsec-optee-ta.h"
/* BSEC secure service access from non-secure */
#define STM32_SMC_BSEC 0x82001003
@@ -25,12 +28,14 @@
struct stm32_romem_cfg {
int size;
u8 lower;
+ bool ta;
};
struct stm32_romem_priv {
void __iomem *base;
struct nvmem_config cfg;
u8 lower;
+ struct tee_context *ctx;
};
static int stm32_romem_read(void *context, unsigned int offset, void *buf,
@@ -138,12 +143,29 @@ static int stm32_bsec_write(void *context, unsigned int offset, void *buf,
return 0;
}
+static int stm32_bsec_pta_read(void *context, unsigned int offset, void *buf,
+ size_t bytes)
+{
+ struct stm32_romem_priv *priv = context;
+
+ return stm32_bsec_optee_ta_read(priv->ctx, offset, buf, bytes);
+}
+
+static int stm32_bsec_pta_write(void *context, unsigned int offset, void *buf,
+ size_t bytes)
+{
+ struct stm32_romem_priv *priv = context;
+
+ return stm32_bsec_optee_ta_write(priv->ctx, priv->lower, offset, buf, bytes);
+}
+
static int stm32_romem_probe(struct platform_device *pdev)
{
const struct stm32_romem_cfg *cfg;
struct device *dev = &pdev->dev;
struct stm32_romem_priv *priv;
struct resource *res;
+ int rc;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -173,15 +195,31 @@ static int stm32_romem_probe(struct platform_device *pdev)
} else {
priv->cfg.size = cfg->size;
priv->lower = cfg->lower;
- priv->cfg.reg_read = stm32_bsec_read;
- priv->cfg.reg_write = stm32_bsec_write;
+ if (cfg->ta) {
+ rc = stm32_bsec_optee_ta_open(&priv->ctx);
+ /* wait for OP-TEE client driver to be up and ready */
+ if (rc)
+ return rc;
+ }
+ if (priv->ctx) {
+ rc = devm_add_action_or_reset(dev, stm32_bsec_optee_ta_close, priv->ctx);
+ if (rc) {
+ dev_err(dev, "devm_add_action_or_reset() failed (%d)\n", rc);
+ return rc;
+ }
+ priv->cfg.reg_read = stm32_bsec_pta_read;
+ priv->cfg.reg_write = stm32_bsec_pta_write;
+ } else {
+ priv->cfg.reg_read = stm32_bsec_read;
+ priv->cfg.reg_write = stm32_bsec_write;
+ }
}
return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg));
}
/*
- * STM32MP15 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
+ * STM32MP15/13 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits)
* => 96 x 32-bits data words
* - Lower: 1K bits, 2:1 redundancy, incremental bit programming
* => 32 (x 32-bits) lower shadow registers = words 0 to 31
@@ -191,6 +229,13 @@ static int stm32_romem_probe(struct platform_device *pdev)
static const struct stm32_romem_cfg stm32mp15_bsec_cfg = {
.size = 384,
.lower = 32,
+ .ta = false,
+};
+
+static const struct stm32_romem_cfg stm32mp13_bsec_cfg = {
+ .size = 384,
+ .lower = 32,
+ .ta = true,
};
static const struct of_device_id stm32_romem_of_match[] = {
@@ -198,7 +243,10 @@ static const struct of_device_id stm32_romem_of_match[] = {
.compatible = "st,stm32mp15-bsec",
.data = (void *)&stm32mp15_bsec_cfg,
}, {
+ .compatible = "st,stm32mp13-bsec",
+ .data = (void *)&stm32mp13_bsec_cfg,
},
+ { /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, stm32_romem_of_match);
--
2.25.1
From: Randy Dunlap <[email protected]>
Convert an empty line to " *" to avoid a kernel-doc warning:
drivers/nvmem/rave-sp-eeprom.c:48: warning: bad line:
Signed-off-by: Randy Dunlap <[email protected]>
Cc: Srinivas Kandagatla <[email protected]>
Cc: Andrey Vostrikov <[email protected]>
Cc: Nikita Yushchenko <[email protected]>
Cc: Andrey Smirnov <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/rave-sp-eeprom.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvmem/rave-sp-eeprom.c b/drivers/nvmem/rave-sp-eeprom.c
index 66699d44f73d..c456011b75e8 100644
--- a/drivers/nvmem/rave-sp-eeprom.c
+++ b/drivers/nvmem/rave-sp-eeprom.c
@@ -45,7 +45,7 @@ enum rave_sp_eeprom_header_size {
* @type: Access type (see enum rave_sp_eeprom_access_type)
* @success: Success flag (Success = 1, Failure = 0)
* @data: Read data
-
+ *
* Note this structure corresponds to RSP_*_EEPROM payload from RAVE
* SP ICD
*/
--
2.25.1
From: Patrick Delaunay <[email protected]>
On STM32MP15x SoC, the SMC backend is optional when OP-TEE is used;
the PTA BSEC should be used as it is done on STM32MP13x platform,
but the BSEC SMC can be also used: it is a legacy mode in OP-TEE,
not recommended but used in previous OP-TEE firmware.
The presence of OP-TEE is dynamically detected in STM32MP15x device tree
and the supported NVMEM backend is dynamically detected:
- PTA with stm32_bsec_pta_find
- SMC with stm32_bsec_check
With OP-TEE but without PTA and SMC detection, the probe is deferred for
STM32MP15x devices.
On STM32MP13x platform, only the PTA is supported with cfg->ta = true
and this detection is skipped.
Signed-off-by: Patrick Delaunay <[email protected]>
Reviewed-by: Etienne Carriere <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/stm32-romem.c | 38 +++++++++++++++++++++++++++++++++----
1 file changed, 34 insertions(+), 4 deletions(-)
diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index 978a63edf297..ba779e26937a 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -159,6 +159,31 @@ static int stm32_bsec_pta_write(void *context, unsigned int offset, void *buf,
return stm32_bsec_optee_ta_write(priv->ctx, priv->lower, offset, buf, bytes);
}
+static bool stm32_bsec_smc_check(void)
+{
+ u32 val;
+ int ret;
+
+ /* check that the OP-TEE support the BSEC SMC (legacy mode) */
+ ret = stm32_bsec_smc(STM32_SMC_READ_SHADOW, 0, 0, &val);
+
+ return !ret;
+}
+
+static bool optee_presence_check(void)
+{
+ struct device_node *np;
+ bool tee_detected = false;
+
+ /* check that the OP-TEE node is present and available. */
+ np = of_find_compatible_node(NULL, NULL, "linaro,optee-tz");
+ if (np && of_device_is_available(np))
+ tee_detected = true;
+ of_node_put(np);
+
+ return tee_detected;
+}
+
static int stm32_romem_probe(struct platform_device *pdev)
{
const struct stm32_romem_cfg *cfg;
@@ -195,11 +220,16 @@ static int stm32_romem_probe(struct platform_device *pdev)
} else {
priv->cfg.size = cfg->size;
priv->lower = cfg->lower;
- if (cfg->ta) {
+ if (cfg->ta || optee_presence_check()) {
rc = stm32_bsec_optee_ta_open(&priv->ctx);
- /* wait for OP-TEE client driver to be up and ready */
- if (rc)
- return rc;
+ if (rc) {
+ /* wait for OP-TEE client driver to be up and ready */
+ if (rc == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ /* BSEC PTA is required or SMC not supported */
+ if (cfg->ta || !stm32_bsec_smc_check())
+ return rc;
+ }
}
if (priv->ctx) {
rc = devm_add_action_or_reset(dev, stm32_bsec_optee_ta_close, priv->ctx);
--
2.25.1
From: Johan Hovold <[email protected]>
There are currently no in-tree users of the Qualcomm SDAM nvmem driver
and there is generally no point in registering a driver that can be
built as a module at subsys init time.
Register the driver at the normal device init time instead and let
driver core sort out the probe order.
Signed-off-by: Johan Hovold <[email protected]>
Reviewed-by: Bjorn Andersson <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/qcom-spmi-sdam.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c
index 8499892044b7..f822790db49e 100644
--- a/drivers/nvmem/qcom-spmi-sdam.c
+++ b/drivers/nvmem/qcom-spmi-sdam.c
@@ -175,18 +175,7 @@ static struct platform_driver sdam_driver = {
},
.probe = sdam_probe,
};
-
-static int __init sdam_init(void)
-{
- return platform_driver_register(&sdam_driver);
-}
-subsys_initcall(sdam_init);
-
-static void __exit sdam_exit(void)
-{
- return platform_driver_unregister(&sdam_driver);
-}
-module_exit(sdam_exit);
+module_platform_driver(sdam_driver);
MODULE_DESCRIPTION("QCOM SPMI SDAM driver");
MODULE_LICENSE("GPL v2");
--
2.25.1
From: Robert Marko <[email protected]>
Document IPQ8074 compatible for QFPROM, its compatible with the generic
QFPROM fallback.
Signed-off-by: Robert Marko <[email protected]>
Acked-by: Krzysztof Kozlowski <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
index 9ddf3cef9e84..2173fe82317d 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -19,6 +19,7 @@ properties:
- qcom,apq8064-qfprom
- qcom,apq8084-qfprom
- qcom,ipq8064-qfprom
+ - qcom,ipq8074-qfprom
- qcom,msm8916-qfprom
- qcom,msm8974-qfprom
- qcom,msm8976-qfprom
--
2.25.1
From: Arnd Bergmann <[email protected]>
The stm32 nvmem driver fails to link as built-in when OPTEE
is a loadable module:
aarch64-linux-ld: drivers/nvmem/stm32-bsec-optee-ta.o: in function `stm32_bsec:
stm32-bsec-optee-ta.c:(.text+0xc8): undefined reference to `tee_client_open_session'
aarch64-linux-ld: drivers/nvmem/stm32-bsec-optee-ta.o: in function `stm32_bsec:
stm32-bsec-optee-ta.c:(.text+0x1fc): undefined reference to `tee_client_open_context'
Change the CONFIG_NVMEM_STM32_ROMEM definition so it can only
be built-in if OPTEE is either built-in or disabled, and
make NVMEM_STM32_BSEC_OPTEE_TA a hidden symbol instead.
Signed-off-by: Arnd Bergmann <[email protected]>
Signed-off-by: Srinivas Kandagatla <[email protected]>
---
drivers/nvmem/Kconfig | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 4d262f69a073..6dec38805041 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -291,8 +291,7 @@ config NVMEM_SPRD_EFUSE
will be called nvmem-sprd-efuse.
config NVMEM_STM32_BSEC_OPTEE_TA
- bool "STM32MP BSEC OP-TEE TA support for nvmem-stm32-romem driver"
- depends on OPTEE
+ def_bool NVMEM_STM32_ROMEM && OPTEE
help
Say y here to enable the accesses to STM32MP SoC OTPs by the OP-TEE
trusted application STM32MP BSEC.
@@ -303,7 +302,7 @@ config NVMEM_STM32_BSEC_OPTEE_TA
config NVMEM_STM32_ROMEM
tristate "STMicroelectronics STM32 factory-programmed memory support"
depends on ARCH_STM32 || COMPILE_TEST
- imply NVMEM_STM32_BSEC_OPTEE_TA
+ depends on OPTEE || !OPTEE
help
Say y here to enable read-only access for STMicroelectronics STM32
factory-programmed memory area.
--
2.25.1
Hi,
Am Montag, 6. Februar 2023, 14:43:46 CET schrieb Srinivas Kandagatla:
> From: Michael Walle <[email protected]>
>
> Sometimes a cell can represend multiple values. For example, a base
> ethernet address stored in the NVMEM can be expanded into multiple
> discreet ones by adding an offset.
>
> For this use case, introduce an index parameter which is then used to
> distiguish between values. This parameter will then be passed to the
> post process hook which can then use it to create different values
> during reading.
>
> At the moment, there is only support for the device tree path. You can
> add the index to the phandle, e.g.
>
> &net {
> nvmem-cells = <&base_mac_address 2>;
> nvmem-cell-names = "mac-address";
> };
>
> &nvmem_provider {
> base_mac_address: base-mac-address@0 {
> #nvmem-cell-cells = <1>;
> reg = <0 6>;
> };
> };
>
> Signed-off-by: Michael Walle <[email protected]>
> Signed-off-by: Srinivas Kandagatla <[email protected]>
> ---
> drivers/nvmem/core.c | 37 ++++++++++++++++++++++++----------
> drivers/nvmem/imx-ocotp.c | 4 ++--
> include/linux/nvmem-provider.h | 4 ++--
> 3 files changed, 30 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index 233c6c275031..30567dd51fba 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -60,6 +60,7 @@ struct nvmem_cell_entry {
> struct nvmem_cell {
> struct nvmem_cell_entry *entry;
> const char *id;
> + int index;
> };
>
> static DEFINE_MUTEX(nvmem_mutex);
> @@ -1122,7 +1123,8 @@ struct nvmem_device *devm_nvmem_device_get(struct
> device *dev, const char *id) }
> EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
>
> -static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
> const char *id) +static struct nvmem_cell *nvmem_create_cell(struct
> nvmem_cell_entry *entry, +
const char *id, int index)
> {
> struct nvmem_cell *cell;
> const char *name = NULL;
> @@ -1141,6 +1143,7 @@ static struct nvmem_cell *nvmem_create_cell(struct
> nvmem_cell_entry *entry, cons
>
> cell->id = name;
> cell->entry = entry;
> + cell->index = index;
>
> return cell;
> }
> @@ -1179,7 +1182,7 @@ nvmem_cell_get_from_lookup(struct device *dev, const
> char *con_id) __nvmem_device_put(nvmem);
> cell = ERR_PTR(-ENOENT);
> } else {
> - cell = nvmem_create_cell(cell_entry,
con_id);
> + cell = nvmem_create_cell(cell_entry,
con_id, 0);
> if (IS_ERR(cell))
> __nvmem_device_put(nvmem);
> }
> @@ -1227,15 +1230,27 @@ struct nvmem_cell *of_nvmem_cell_get(struct
> device_node *np, const char *id) struct nvmem_device *nvmem;
> struct nvmem_cell_entry *cell_entry;
> struct nvmem_cell *cell;
> + struct of_phandle_args cell_spec;
> int index = 0;
> + int cell_index = 0;
> + int ret;
>
> /* if cell name exists, find index to the name */
> if (id)
> index = of_property_match_string(np, "nvmem-cell-names",
id);
>
> - cell_np = of_parse_phandle(np, "nvmem-cells", index);
> - if (!cell_np)
> - return ERR_PTR(-ENOENT);
> + ret = of_parse_phandle_with_optional_args(np, "nvmem-cells",
> + "#nvmem-cell-
cells",
> + index,
&cell_spec);
> + if (ret)
> + return ERR_PTR(ret);
This change introduce a regression (again, see [1] for that).
dp83867_of_init_io_impedance calls of_nvmem_cell_get() for cell
'io_impedance_ctrl'. If this does not exist, 'nvmem-cell-names' does not exist
as well, of_property_match_string returns -22 for index.
__of_parse_phandle_with_args eventually returns -EINVAL for this invalid
index. -ENOENT was returned before.
There was a bugfix [2] for this, but it's not in linux-next.
Best regards,
Alexander
[1] https://lore.kernel.org/lkml/2143916.GUh0CODmnK@steina-w/
[2] https://lore.kernel.org/lkml/[email protected]/T/
> +
> + if (cell_spec.args_count > 1)
> + return ERR_PTR(-EINVAL);
> +
> + cell_np = cell_spec.np;
> + if (cell_spec.args_count)
> + cell_index = cell_spec.args[0];
>
> nvmem_np = of_get_parent(cell_np);
> if (!nvmem_np) {
> @@ -1257,7 +1272,7 @@ struct nvmem_cell *of_nvmem_cell_get(struct
> device_node *np, const char *id) return ERR_PTR(-ENOENT);
> }
>
> - cell = nvmem_create_cell(cell_entry, id);
> + cell = nvmem_create_cell(cell_entry, id, cell_index);
> if (IS_ERR(cell))
> __nvmem_device_put(nvmem);
>
> @@ -1410,8 +1425,8 @@ static void nvmem_shift_read_buffer_in_place(struct
> nvmem_cell_entry *cell, void }
>
> static int __nvmem_cell_read(struct nvmem_device *nvmem,
> - struct nvmem_cell_entry *cell,
> - void *buf, size_t *len, const char *id)
> + struct nvmem_cell_entry *cell,
> + void *buf, size_t *len, const char *id, int
index)
> {
> int rc;
>
> @@ -1425,7 +1440,7 @@ static int __nvmem_cell_read(struct nvmem_device
> *nvmem, nvmem_shift_read_buffer_in_place(cell, buf);
>
> if (nvmem->cell_post_process) {
> - rc = nvmem->cell_post_process(nvmem->priv, id,
> + rc = nvmem->cell_post_process(nvmem->priv, id, index,
> cell->offset, buf,
cell->bytes);
> if (rc)
> return rc;
> @@ -1460,7 +1475,7 @@ void *nvmem_cell_read(struct nvmem_cell *cell, size_t
> *len) if (!buf)
> return ERR_PTR(-ENOMEM);
>
> - rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id);
> + rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id,
> cell->index); if (rc) {
> kfree(buf);
> return ERR_PTR(rc);
> @@ -1773,7 +1788,7 @@ ssize_t nvmem_device_cell_read(struct nvmem_device
> *nvmem, if (rc)
> return rc;
>
> - rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL);
> + rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0);
> if (rc)
> return rc;
>
> diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
> index 14284e866f26..e9b52ecb3f72 100644
> --- a/drivers/nvmem/imx-ocotp.c
> +++ b/drivers/nvmem/imx-ocotp.c
> @@ -222,8 +222,8 @@ static int imx_ocotp_read(void *context, unsigned int
> offset, return ret;
> }
>
> -static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int
> offset, - void *data, size_t bytes)
> +static int imx_ocotp_cell_pp(void *context, const char *id, int index,
> + unsigned int offset, void *data, size_t
bytes)
> {
> struct ocotp_priv *priv = context;
>
> diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
> index bb15c9234e21..55181d837969 100644
> --- a/include/linux/nvmem-provider.h
> +++ b/include/linux/nvmem-provider.h
> @@ -20,8 +20,8 @@ typedef int (*nvmem_reg_read_t)(void *priv, unsigned int
> offset, typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset,
> void *val, size_t bytes);
> /* used for vendor specific post processing of cell data */
> -typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id,
> unsigned int offset, - void
*buf, size_t bytes);
> +typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, int
> index, + unsigned int offset, void
*buf, size_t bytes);
>
> enum nvmem_type {
> NVMEM_TYPE_UNKNOWN = 0,