diff options
Diffstat (limited to 'arm-sunxi-nvmem-fixH3.patch')
-rw-r--r-- | arm-sunxi-nvmem-fixH3.patch | 131 |
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 |