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>
This commit is contained in:
Родитель
80b820cae4
Коммит
0ab09d651b
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче