summaryrefslogtreecommitdiffstats
path: root/arm-sunxi-nvmem-fixH3.patch
diff options
context:
space:
mode:
Diffstat (limited to 'arm-sunxi-nvmem-fixH3.patch')
-rw-r--r--arm-sunxi-nvmem-fixH3.patch131
1 files changed, 131 insertions, 0 deletions
diff --git a/arm-sunxi-nvmem-fixH3.patch b/arm-sunxi-nvmem-fixH3.patch
new file mode 100644
index 000000000..415885d4c
--- /dev/null
+++ b/arm-sunxi-nvmem-fixH3.patch
@@ -0,0 +1,131 @@
+From 0ab09d651b5858f9bc7d5f74e725334a661828e0 Mon Sep 17 00:00:00 2001
+From: Icenowy Zheng <icenowy@aosc.io>
+Date: Fri, 9 Mar 2018 14:47:17 +0000
+Subject: nvmem: sunxi-sid: fix H3 SID controller support
+
+It seems that doing some operation will make the value pre-read on H3
+SID controller wrong again, so all operation should be performed by
+register.
+
+Change the SID reading to use register only.
+
+Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
+Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/nvmem/sunxi_sid.c | 71 +++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 50 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
+index 99bd54d..26bb637 100644
+--- a/drivers/nvmem/sunxi_sid.c
++++ b/drivers/nvmem/sunxi_sid.c
+@@ -85,13 +85,14 @@ static int sunxi_sid_read(void *context, unsigned int offset,
+ }
+
+ static int sun8i_sid_register_readout(const struct sunxi_sid *sid,
+- const unsigned int word)
++ const unsigned int offset,
++ u32 *out)
+ {
+ u32 reg_val;
+ int ret;
+
+ /* Set word, lock access, and set read command */
+- reg_val = (word & SUN8I_SID_OFFSET_MASK)
++ reg_val = (offset & SUN8I_SID_OFFSET_MASK)
+ << SUN8I_SID_OFFSET_SHIFT;
+ reg_val |= SUN8I_SID_OP_LOCK | SUN8I_SID_READ;
+ writel(reg_val, sid->base + SUN8I_SID_PRCTL);
+@@ -101,7 +102,49 @@ static int sun8i_sid_register_readout(const struct sunxi_sid *sid,
+ if (ret)
+ return ret;
+
++ if (out)
++ *out = readl(sid->base + SUN8I_SID_RDKEY);
++
+ writel(0, sid->base + SUN8I_SID_PRCTL);
++
++ return 0;
++}
++
++/*
++ * On Allwinner H3, the value on the 0x200 offset of the SID controller seems
++ * to be not reliable at all.
++ * Read by the registers instead.
++ */
++static int sun8i_sid_read_byte_by_reg(const struct sunxi_sid *sid,
++ const unsigned int offset,
++ u8 *out)
++{
++ u32 word;
++ int ret;
++
++ ret = sun8i_sid_register_readout(sid, offset & ~0x03, &word);
++
++ if (ret)
++ return ret;
++
++ *out = (word >> ((offset & 0x3) * 8)) & 0xff;
++
++ return 0;
++}
++
++static int sun8i_sid_read_by_reg(void *context, unsigned int offset,
++ void *val, size_t bytes)
++{
++ struct sunxi_sid *sid = context;
++ u8 *buf = val;
++ int ret;
++
++ while (bytes--) {
++ ret = sun8i_sid_read_byte_by_reg(sid, offset++, buf++);
++ if (ret)
++ return ret;
++ }
++
+ return 0;
+ }
+
+@@ -131,26 +174,12 @@ static int sunxi_sid_probe(struct platform_device *pdev)
+
+ size = cfg->size;
+
+- if (cfg->need_register_readout) {
+- /*
+- * H3's SID controller have a bug that the value at 0x200
+- * offset is not the correct value when the hardware is reseted.
+- * However, after doing a register-based read operation, the
+- * value become right.
+- * Do a full read operation here, but ignore its value
+- * (as it's more fast to read by direct MMIO value than
+- * with registers)
+- */
+- for (i = 0; i < (size >> 2); i++) {
+- ret = sun8i_sid_register_readout(sid, i);
+- if (ret)
+- return ret;
+- }
+- }
+-
+ econfig.size = size;
+ econfig.dev = dev;
+- econfig.reg_read = sunxi_sid_read;
++ if (cfg->need_register_readout)
++ econfig.reg_read = sun8i_sid_read_by_reg;
++ else
++ econfig.reg_read = sunxi_sid_read;
+ econfig.priv = sid;
+ nvmem = nvmem_register(&econfig);
+ if (IS_ERR(nvmem))
+@@ -163,7 +192,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
+ }
+
+ for (i = 0; i < size; i++)
+- randomness[i] = sunxi_sid_read_byte(sid, i);
++ econfig.reg_read(sid, i, &randomness[i], 1);
+
+ add_device_randomness(randomness, size);
+ kfree(randomness);
+--
+cgit v1.1