* [PATCH v3 1/5] nvmem: core: fix bit offsets of more than one byte
2025-01-04 6:19 [PATCH v3 0/5] nvmem: qfprom: add Qualcomm SAR2130P support Dmitry Baryshkov
@ 2025-01-04 6:19 ` Dmitry Baryshkov
2025-01-08 21:47 ` Akhil P Oommen
2025-01-04 6:19 ` [PATCH v3 2/5] nvmem: core: verify cell's raw_len Dmitry Baryshkov
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Dmitry Baryshkov @ 2025-01-04 6:19 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Akhil P Oommen, linux-arm-msm, devicetree, linux-kernel
If the NVMEM specifies a stride to access data, reading particular cell
might require bit offset that is bigger than one byte. Rework NVMEM core
code to support bit offsets of more than 8 bits.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/nvmem/core.c | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index d6494dfc20a7324bde6415776dcabbb0bfdd334b..c0af43a37195c3869507a203b370615309aeee67 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -834,7 +834,9 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
if (addr && len == (2 * sizeof(u32))) {
info.bit_offset = be32_to_cpup(addr++);
info.nbits = be32_to_cpup(addr);
- if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
+ if (info.bit_offset >= BITS_PER_BYTE * info.bytes ||
+ info.nbits < 1 ||
+ info.bit_offset + info.nbits >= BITS_PER_BYTE * info.bytes) {
dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
of_node_put(child);
return -EINVAL;
@@ -1627,21 +1629,29 @@ EXPORT_SYMBOL_GPL(nvmem_cell_put);
static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf)
{
u8 *p, *b;
- int i, extra, bit_offset = cell->bit_offset;
+ int i, extra, bytes_offset;
+ int bit_offset = cell->bit_offset;
p = b = buf;
- if (bit_offset) {
+
+ bytes_offset = bit_offset / BITS_PER_BYTE;
+ b += bytes_offset;
+ bit_offset %= BITS_PER_BYTE;
+
+ if (bit_offset % BITS_PER_BYTE) {
/* First shift */
- *b++ >>= bit_offset;
+ *p = *b++ >> bit_offset;
/* setup rest of the bytes if any */
for (i = 1; i < cell->bytes; i++) {
/* Get bits from next byte and shift them towards msb */
- *p |= *b << (BITS_PER_BYTE - bit_offset);
+ *p++ |= *b << (BITS_PER_BYTE - bit_offset);
- p = b;
- *b++ >>= bit_offset;
+ *p = *b++ >> bit_offset;
}
+ } else if (p != b) {
+ memmove(p, b, cell->bytes - bytes_offset);
+ p += cell->bytes - 1;
} else {
/* point to the msb */
p += cell->bytes - 1;
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 1/5] nvmem: core: fix bit offsets of more than one byte
2025-01-04 6:19 ` [PATCH v3 1/5] nvmem: core: fix bit offsets of more than one byte Dmitry Baryshkov
@ 2025-01-08 21:47 ` Akhil P Oommen
2025-01-09 4:30 ` Dmitry Baryshkov
0 siblings, 1 reply; 9+ messages in thread
From: Akhil P Oommen @ 2025-01-08 21:47 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: linux-arm-msm, devicetree, linux-kernel, Srinivas Kandagatla,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
On 1/4/2025 11:49 AM, Dmitry Baryshkov wrote:
> If the NVMEM specifies a stride to access data, reading particular cell
> might require bit offset that is bigger than one byte. Rework NVMEM core
> code to support bit offsets of more than 8 bits.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> drivers/nvmem/core.c | 24 +++++++++++++++++-------
> 1 file changed, 17 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index d6494dfc20a7324bde6415776dcabbb0bfdd334b..c0af43a37195c3869507a203b370615309aeee67 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -834,7 +834,9 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
> if (addr && len == (2 * sizeof(u32))) {
> info.bit_offset = be32_to_cpup(addr++);
> info.nbits = be32_to_cpup(addr);
> - if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
> + if (info.bit_offset >= BITS_PER_BYTE * info.bytes ||
> + info.nbits < 1 ||
> + info.bit_offset + info.nbits >= BITS_PER_BYTE * info.bytes) {
Should it be ">" check instead of ">=" check here?
For eg: bit_offset = 7, nbits = 1 and info.bytes = 1 is valid, isn't it?
-Akhil
> dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
> of_node_put(child);
> return -EINVAL;
> @@ -1627,21 +1629,29 @@ EXPORT_SYMBOL_GPL(nvmem_cell_put);
> static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf)
> {
> u8 *p, *b;
> - int i, extra, bit_offset = cell->bit_offset;
> + int i, extra, bytes_offset;
> + int bit_offset = cell->bit_offset;
>
> p = b = buf;
> - if (bit_offset) {
> +
> + bytes_offset = bit_offset / BITS_PER_BYTE;
> + b += bytes_offset;
> + bit_offset %= BITS_PER_BYTE;
> +
> + if (bit_offset % BITS_PER_BYTE) {
> /* First shift */
> - *b++ >>= bit_offset;
> + *p = *b++ >> bit_offset;
>
> /* setup rest of the bytes if any */
> for (i = 1; i < cell->bytes; i++) {
> /* Get bits from next byte and shift them towards msb */
> - *p |= *b << (BITS_PER_BYTE - bit_offset);
> + *p++ |= *b << (BITS_PER_BYTE - bit_offset);
>
> - p = b;
> - *b++ >>= bit_offset;
> + *p = *b++ >> bit_offset;
> }
> + } else if (p != b) {
> + memmove(p, b, cell->bytes - bytes_offset);
> + p += cell->bytes - 1;
> } else {
> /* point to the msb */
> p += cell->bytes - 1;
>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v3 1/5] nvmem: core: fix bit offsets of more than one byte
2025-01-08 21:47 ` Akhil P Oommen
@ 2025-01-09 4:30 ` Dmitry Baryshkov
0 siblings, 0 replies; 9+ messages in thread
From: Dmitry Baryshkov @ 2025-01-09 4:30 UTC (permalink / raw)
To: Akhil P Oommen
Cc: linux-arm-msm, devicetree, linux-kernel, Srinivas Kandagatla,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
On Thu, Jan 09, 2025 at 03:17:08AM +0530, Akhil P Oommen wrote:
> On 1/4/2025 11:49 AM, Dmitry Baryshkov wrote:
> > If the NVMEM specifies a stride to access data, reading particular cell
> > might require bit offset that is bigger than one byte. Rework NVMEM core
> > code to support bit offsets of more than 8 bits.
> >
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > ---
> > drivers/nvmem/core.c | 24 +++++++++++++++++-------
> > 1 file changed, 17 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> > index d6494dfc20a7324bde6415776dcabbb0bfdd334b..c0af43a37195c3869507a203b370615309aeee67 100644
> > --- a/drivers/nvmem/core.c
> > +++ b/drivers/nvmem/core.c
> > @@ -834,7 +834,9 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
> > if (addr && len == (2 * sizeof(u32))) {
> > info.bit_offset = be32_to_cpup(addr++);
> > info.nbits = be32_to_cpup(addr);
> > - if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
> > + if (info.bit_offset >= BITS_PER_BYTE * info.bytes ||
> > + info.nbits < 1 ||
> > + info.bit_offset + info.nbits >= BITS_PER_BYTE * info.bytes) {
>
> Should it be ">" check instead of ">=" check here?
> For eg: bit_offset = 7, nbits = 1 and info.bytes = 1 is valid, isn't it?
Indeed. I'll send v-next.
>
> -Akhil
>
> > dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
> > of_node_put(child);
> > return -EINVAL;
> > @@ -1627,21 +1629,29 @@ EXPORT_SYMBOL_GPL(nvmem_cell_put);
> > static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf)
> > {
> > u8 *p, *b;
> > - int i, extra, bit_offset = cell->bit_offset;
> > + int i, extra, bytes_offset;
> > + int bit_offset = cell->bit_offset;
> >
> > p = b = buf;
> > - if (bit_offset) {
> > +
> > + bytes_offset = bit_offset / BITS_PER_BYTE;
> > + b += bytes_offset;
> > + bit_offset %= BITS_PER_BYTE;
> > +
> > + if (bit_offset % BITS_PER_BYTE) {
> > /* First shift */
> > - *b++ >>= bit_offset;
> > + *p = *b++ >> bit_offset;
> >
> > /* setup rest of the bytes if any */
> > for (i = 1; i < cell->bytes; i++) {
> > /* Get bits from next byte and shift them towards msb */
> > - *p |= *b << (BITS_PER_BYTE - bit_offset);
> > + *p++ |= *b << (BITS_PER_BYTE - bit_offset);
> >
> > - p = b;
> > - *b++ >>= bit_offset;
> > + *p = *b++ >> bit_offset;
> > }
> > + } else if (p != b) {
> > + memmove(p, b, cell->bytes - bytes_offset);
> > + p += cell->bytes - 1;
> > } else {
> > /* point to the msb */
> > p += cell->bytes - 1;
> >
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 2/5] nvmem: core: verify cell's raw_len
2025-01-04 6:19 [PATCH v3 0/5] nvmem: qfprom: add Qualcomm SAR2130P support Dmitry Baryshkov
2025-01-04 6:19 ` [PATCH v3 1/5] nvmem: core: fix bit offsets of more than one byte Dmitry Baryshkov
@ 2025-01-04 6:19 ` Dmitry Baryshkov
2025-01-04 6:19 ` [PATCH v3 3/5] nvmem: core: update raw_len if the bit reading is required Dmitry Baryshkov
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Dmitry Baryshkov @ 2025-01-04 6:19 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Akhil P Oommen, linux-arm-msm, devicetree, linux-kernel
Check that the NVMEM cell's raw_len is a aligned to word_size. Otherwise
Otherwise drivers might face incomplete read while accessing the last
part of the NVMEM cell.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/nvmem/core.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index c0af43a37195c3869507a203b370615309aeee67..a03a3006bd611ea6e91703cd19c2842bd4f56659 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -602,6 +602,14 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem,
return -EINVAL;
}
+ if (!IS_ALIGNED(cell->raw_len, nvmem->word_size)) {
+ dev_err(&nvmem->dev,
+ "cell %s raw len %zd unaligned to nvmem word size %d\n",
+ cell->name ?: "<unknown>", cell->raw_len,
+ nvmem->word_size);
+ return -EINVAL;
+ }
+
return 0;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 3/5] nvmem: core: update raw_len if the bit reading is required
2025-01-04 6:19 [PATCH v3 0/5] nvmem: qfprom: add Qualcomm SAR2130P support Dmitry Baryshkov
2025-01-04 6:19 ` [PATCH v3 1/5] nvmem: core: fix bit offsets of more than one byte Dmitry Baryshkov
2025-01-04 6:19 ` [PATCH v3 2/5] nvmem: core: verify cell's raw_len Dmitry Baryshkov
@ 2025-01-04 6:19 ` Dmitry Baryshkov
2025-01-04 6:19 ` [PATCH v3 4/5] nvmem: qfprom: switch to 4-byte aligned reads Dmitry Baryshkov
2025-01-04 6:19 ` [PATCH v3 5/5] dt-bindings: nvmem: qcom,qfprom: Add SAR2130P compatible Dmitry Baryshkov
4 siblings, 0 replies; 9+ messages in thread
From: Dmitry Baryshkov @ 2025-01-04 6:19 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Akhil P Oommen, linux-arm-msm, devicetree, linux-kernel
If NVMEM cell uses bit offset or specifies bit truncation, update
raw_len manually (following the cell->bytes update), ensuring that the
NVMEM access is still word-aligned.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/nvmem/core.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index a03a3006bd611ea6e91703cd19c2842bd4f56659..17b320bcbe207aed8a32aa2cc7d8dab9b58c13cf 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -591,9 +591,11 @@ static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem,
cell->nbits = info->nbits;
cell->np = info->np;
- if (cell->nbits)
+ if (cell->nbits) {
cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
BITS_PER_BYTE);
+ cell->raw_len = ALIGN(cell->bytes, nvmem->word_size);
+ }
if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
dev_err(&nvmem->dev,
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 4/5] nvmem: qfprom: switch to 4-byte aligned reads
2025-01-04 6:19 [PATCH v3 0/5] nvmem: qfprom: add Qualcomm SAR2130P support Dmitry Baryshkov
` (2 preceding siblings ...)
2025-01-04 6:19 ` [PATCH v3 3/5] nvmem: core: update raw_len if the bit reading is required Dmitry Baryshkov
@ 2025-01-04 6:19 ` Dmitry Baryshkov
2025-01-04 6:19 ` [PATCH v3 5/5] dt-bindings: nvmem: qcom,qfprom: Add SAR2130P compatible Dmitry Baryshkov
4 siblings, 0 replies; 9+ messages in thread
From: Dmitry Baryshkov @ 2025-01-04 6:19 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Akhil P Oommen, linux-arm-msm, devicetree, linux-kernel
All platforms since Snapdragon 8 Gen1 (SM8450) require using 4-byte
reads to access QFPROM data. While older platforms were more than happy
with 1-byte reads, change the qfprom driver to use 4-byte reads for all
the platforms. Specify stride and word size of 4 bytes. To retain
compatibility with the existing DT and to simplify porting data from
vendor kernels, use fixup_dt_cell_info in order to bump alignment
requirements.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
drivers/nvmem/qfprom.c | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
index 116a39e804c70b4a0374f8ea3ac6ba1dd612109d..a872c640b8c5a558da9ea00e3804c904f8987247 100644
--- a/drivers/nvmem/qfprom.c
+++ b/drivers/nvmem/qfprom.c
@@ -321,19 +321,32 @@ 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;
+ u32 *val = _val;
void __iomem *base = priv->qfpcorrected;
+ int words = DIV_ROUND_UP(bytes, sizeof(u32));
+ int i;
if (read_raw_data && priv->qfpraw)
base = priv->qfpraw;
- while (words--)
- *val++ = readb(base + reg + i++);
+ for (i = 0; i < words; i++)
+ *val++ = readl(base + reg + i * sizeof(u32));
return 0;
}
+/* Align reads to word boundary */
+static void qfprom_fixup_dt_cell_info(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *cell)
+{
+ unsigned int byte_offset = cell->offset % sizeof(u32);
+
+ cell->bit_offset += byte_offset * BITS_PER_BYTE;
+ cell->offset -= byte_offset;
+ if (byte_offset && !cell->nbits)
+ cell->nbits = cell->bytes * BITS_PER_BYTE;
+}
+
static void qfprom_runtime_disable(void *data)
{
pm_runtime_disable(data);
@@ -358,10 +371,11 @@ static int qfprom_probe(struct platform_device *pdev)
struct nvmem_config econfig = {
.name = "qfprom",
.add_legacy_fixed_of_cells = true,
- .stride = 1,
- .word_size = 1,
+ .stride = 4,
+ .word_size = 4,
.id = NVMEM_DEVID_AUTO,
.reg_read = qfprom_reg_read,
+ .fixup_dt_cell_info = qfprom_fixup_dt_cell_info,
};
struct device *dev = &pdev->dev;
struct resource *res;
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v3 5/5] dt-bindings: nvmem: qcom,qfprom: Add SAR2130P compatible
2025-01-04 6:19 [PATCH v3 0/5] nvmem: qfprom: add Qualcomm SAR2130P support Dmitry Baryshkov
` (3 preceding siblings ...)
2025-01-04 6:19 ` [PATCH v3 4/5] nvmem: qfprom: switch to 4-byte aligned reads Dmitry Baryshkov
@ 2025-01-04 6:19 ` Dmitry Baryshkov
2025-01-07 15:14 ` Rob Herring (Arm)
4 siblings, 1 reply; 9+ messages in thread
From: Dmitry Baryshkov @ 2025-01-04 6:19 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Akhil P Oommen, linux-arm-msm, devicetree, linux-kernel
Document compatible for the QFPROM on SAR2130P platform.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
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 80845c722ae46611c722effeaaf014a0caf76e4a..9755b31946bf9d4c1055a993145d06c274b61a37 100644
--- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
+++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
@@ -32,6 +32,7 @@ properties:
- qcom,msm8998-qfprom
- qcom,qcm2290-qfprom
- qcom,qcs404-qfprom
+ - qcom,sar2130p-qfprom
- qcom,sc7180-qfprom
- qcom,sc7280-qfprom
- qcom,sc8280xp-qfprom
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH v3 5/5] dt-bindings: nvmem: qcom,qfprom: Add SAR2130P compatible
2025-01-04 6:19 ` [PATCH v3 5/5] dt-bindings: nvmem: qcom,qfprom: Add SAR2130P compatible Dmitry Baryshkov
@ 2025-01-07 15:14 ` Rob Herring (Arm)
0 siblings, 0 replies; 9+ messages in thread
From: Rob Herring (Arm) @ 2025-01-07 15:14 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: linux-arm-msm, Akhil P Oommen, devicetree, linux-kernel,
Krzysztof Kozlowski, Srinivas Kandagatla, Conor Dooley
On Sat, 04 Jan 2025 08:19:16 +0200, Dmitry Baryshkov wrote:
> Document compatible for the QFPROM on SAR2130P platform.
>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 1 +
> 1 file changed, 1 insertion(+)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 9+ messages in thread