Skip to content

Commit 0ab09d6

Browse files
Icenowygregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Srinivas Kandagatla <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 80b820c commit 0ab09d6

File tree

1 file changed

+50
-21
lines changed

1 file changed

+50
-21
lines changed

drivers/nvmem/sunxi_sid.c

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,14 @@ static int sunxi_sid_read(void *context, unsigned int offset,
8585
}
8686

8787
static int sun8i_sid_register_readout(const struct sunxi_sid *sid,
88-
const unsigned int word)
88+
const unsigned int offset,
89+
u32 *out)
8990
{
9091
u32 reg_val;
9192
int ret;
9293

9394
/* Set word, lock access, and set read command */
94-
reg_val = (word & SUN8I_SID_OFFSET_MASK)
95+
reg_val = (offset & SUN8I_SID_OFFSET_MASK)
9596
<< SUN8I_SID_OFFSET_SHIFT;
9697
reg_val |= SUN8I_SID_OP_LOCK | SUN8I_SID_READ;
9798
writel(reg_val, sid->base + SUN8I_SID_PRCTL);
@@ -101,7 +102,49 @@ static int sun8i_sid_register_readout(const struct sunxi_sid *sid,
101102
if (ret)
102103
return ret;
103104

105+
if (out)
106+
*out = readl(sid->base + SUN8I_SID_RDKEY);
107+
104108
writel(0, sid->base + SUN8I_SID_PRCTL);
109+
110+
return 0;
111+
}
112+
113+
/*
114+
* On Allwinner H3, the value on the 0x200 offset of the SID controller seems
115+
* to be not reliable at all.
116+
* Read by the registers instead.
117+
*/
118+
static int sun8i_sid_read_byte_by_reg(const struct sunxi_sid *sid,
119+
const unsigned int offset,
120+
u8 *out)
121+
{
122+
u32 word;
123+
int ret;
124+
125+
ret = sun8i_sid_register_readout(sid, offset & ~0x03, &word);
126+
127+
if (ret)
128+
return ret;
129+
130+
*out = (word >> ((offset & 0x3) * 8)) & 0xff;
131+
132+
return 0;
133+
}
134+
135+
static int sun8i_sid_read_by_reg(void *context, unsigned int offset,
136+
void *val, size_t bytes)
137+
{
138+
struct sunxi_sid *sid = context;
139+
u8 *buf = val;
140+
int ret;
141+
142+
while (bytes--) {
143+
ret = sun8i_sid_read_byte_by_reg(sid, offset++, buf++);
144+
if (ret)
145+
return ret;
146+
}
147+
105148
return 0;
106149
}
107150

@@ -131,26 +174,12 @@ static int sunxi_sid_probe(struct platform_device *pdev)
131174

132175
size = cfg->size;
133176

134-
if (cfg->need_register_readout) {
135-
/*
136-
* H3's SID controller have a bug that the value at 0x200
137-
* offset is not the correct value when the hardware is reseted.
138-
* However, after doing a register-based read operation, the
139-
* value become right.
140-
* Do a full read operation here, but ignore its value
141-
* (as it's more fast to read by direct MMIO value than
142-
* with registers)
143-
*/
144-
for (i = 0; i < (size >> 2); i++) {
145-
ret = sun8i_sid_register_readout(sid, i);
146-
if (ret)
147-
return ret;
148-
}
149-
}
150-
151177
econfig.size = size;
152178
econfig.dev = dev;
153-
econfig.reg_read = sunxi_sid_read;
179+
if (cfg->need_register_readout)
180+
econfig.reg_read = sun8i_sid_read_by_reg;
181+
else
182+
econfig.reg_read = sunxi_sid_read;
154183
econfig.priv = sid;
155184
nvmem = nvmem_register(&econfig);
156185
if (IS_ERR(nvmem))
@@ -163,7 +192,7 @@ static int sunxi_sid_probe(struct platform_device *pdev)
163192
}
164193

165194
for (i = 0; i < size; i++)
166-
randomness[i] = sunxi_sid_read_byte(sid, i);
195+
econfig.reg_read(sid, i, &randomness[i], 1);
167196

168197
add_device_randomness(randomness, size);
169198
kfree(randomness);

0 commit comments

Comments
 (0)