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") Signed-off-by: Samuel Holland <samuel@xxxxxxxxxxxx> --- drivers/nvmem/sunxi_sid.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c index 5750e1f4bcdb..92dfe4cb10e3 100644 --- a/drivers/nvmem/sunxi_sid.c +++ b/drivers/nvmem/sunxi_sid.c @@ -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; } -- 2.35.1