632b01cb2ac8f380e39bc7297cec7379458c2457
[openwrt/openwrt.git] / target / linux / generic / backport-5.10 / 812-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch
1 From c151d5ed8e8fe0474bd61dce7f2076ca5916c683 Mon Sep 17 00:00:00 2001
2 From: Samuel Holland <samuel@sholland.org>
3 Date: Fri, 27 Jan 2023 10:40:07 +0000
4 Subject: [PATCH] nvmem: sunxi_sid: Always use 32-bit MMIO reads
5
6 The SID SRAM on at least some SoCs (A64 and D1) returns different values
7 when read with bus cycles narrower than 32 bits. This is not immediately
8 obvious, because memcpy_fromio() uses word-size accesses as long as
9 enough data is being copied.
10
11 The vendor driver always uses 32-bit MMIO reads, so do the same here.
12 This is faster than the register-based method, which is currently used
13 as a workaround on A64. And it fixes the values returned on D1, where
14 the SRAM method was being used.
15
16 The special case for the last word is needed to maintain .word_size == 1
17 for sysfs ABI compatibility, as noted previously in commit de2a3eaea552
18 ("nvmem: sunxi_sid: Optimize register read-out method").
19
20 Fixes: 07ae4fde9efa ("nvmem: sunxi_sid: Add support for D1 variant")
21 Cc: stable@vger.kernel.org
22 Tested-by: Heiko Stuebner <heiko@sntech.de>
23 Signed-off-by: Samuel Holland <samuel@sholland.org>
24 Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
25 Link: https://lore.kernel.org/r/20230127104015.23839-3-srinivas.kandagatla@linaro.org
26 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
27 ---
28 drivers/nvmem/sunxi_sid.c | 15 ++++++++++++++-
29 1 file changed, 14 insertions(+), 1 deletion(-)
30
31 --- a/drivers/nvmem/sunxi_sid.c
32 +++ b/drivers/nvmem/sunxi_sid.c
33 @@ -41,8 +41,21 @@ static int sunxi_sid_read(void *context,
34 void *val, size_t bytes)
35 {
36 struct sunxi_sid *sid = context;
37 + u32 word;
38
39 - memcpy_fromio(val, sid->base + sid->value_offset + offset, bytes);
40 + /* .stride = 4 so offset is guaranteed to be aligned */
41 + __ioread32_copy(val, sid->base + sid->value_offset + offset, bytes / 4);
42 +
43 + val += round_down(bytes, 4);
44 + offset += round_down(bytes, 4);
45 + bytes = bytes % 4;
46 +
47 + if (!bytes)
48 + return 0;
49 +
50 + /* Handle any trailing bytes */
51 + word = readl_relaxed(sid->base + sid->value_offset + offset);
52 + memcpy(val, &word, bytes);
53
54 return 0;
55 }