nvmem: sunxi_sid: Always use 32-bit MMIO reads
authorSamuel Holland <samuel@sholland.org>
Fri, 27 Jan 2023 10:40:07 +0000 (10:40 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 28 Jan 2023 13:36:28 +0000 (14:36 +0100)
The SID SRAM on at least some SoCs (A64 and D1) returns different values
when read with bus cycles narrower than 32 bits. This is not immediately
obvious, because memcpy_fromio() uses word-size accesses as long as
enough data is being copied.

The vendor driver always uses 32-bit MMIO reads, so do the same here.
This is faster than the register-based method, which is currently used
as a workaround on A64. And it fixes the values returned on D1, where
the SRAM method was being used.

The special case for the last word is needed to maintain .word_size == 1
for sysfs ABI compatibility, as noted previously in commit de2a3eaea552
("nvmem: sunxi_sid: Optimize register read-out method").

Fixes: 07ae4fde9efa ("nvmem: sunxi_sid: Add support for D1 variant")
Cc: stable@vger.kernel.org
Tested-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Samuel Holland <samuel@sholland.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20230127104015.23839-3-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/nvmem/sunxi_sid.c

index 5750e1f4bcdbbf682d65164a7164483af96af49a..92dfe4cb10e38617ebfc163f2c33cfd2d58abcfb 100644 (file)
@@ -41,8 +41,21 @@ static int sunxi_sid_read(void *context, unsigned int offset,
                          void *val, size_t bytes)
 {
        struct sunxi_sid *sid = context;
+       u32 word;
+
+       /* .stride = 4 so offset is guaranteed to be aligned */
+       __ioread32_copy(val, sid->base + sid->value_offset + offset, bytes / 4);
 
-       memcpy_fromio(val, sid->base + sid->value_offset + offset, bytes);
+       val += round_down(bytes, 4);
+       offset += round_down(bytes, 4);
+       bytes = bytes % 4;
+
+       if (!bytes)
+               return 0;
+
+       /* Handle any trailing bytes */
+       word = readl_relaxed(sid->base + sid->value_offset + offset);
+       memcpy(val, &word, bytes);
 
        return 0;
 }