diff mbox series

[v3,3/5] nvmem: imx-ocotp: Ensure the RELAX field is non-zero

Message ID 20190419171927.24269-4-pure.logic@nexus-software.ie (mailing list archive)
State New, archived
Headers show
Series Add i.MX8MM support | expand

Commit Message

Bryan O'Donoghue April 19, 2019, 5:19 p.m. UTC
The RELAX field of the OCOTP block quote "specifies the time to add to all
default timing parameters other than the Tpgm and Trd. It is given in
number of ipg_clk periods".

On the i.MX8MM the calculation for the RELAX value is turning out to be
zero which is not a problem for programming OTP values but, does
subsequently mess up reloading the OTP shadow registers.

This patch ensures the RELAX field is at least one ipg_clk cycle, which
seems like a pretty obvious floor to place on a value such as this.

Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
---
 drivers/nvmem/imx-ocotp.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Leonard Crestez April 22, 2019, 10:28 a.m. UTC | #1
On 4/19/2019 8:19 PM, Bryan O'Donoghue wrote:
> The RELAX field of the OCOTP block quote "specifies the time to add to all
> default timing parameters other than the Tpgm and Trd. It is given in
> number of ipg_clk periods".
> 
> On the i.MX8MM the calculation for the RELAX value is turning out to be
> zero which is not a problem for programming OTP values but, does
> subsequently mess up reloading the OTP shadow registers.
> 
> This patch ensures the RELAX field is at least one ipg_clk cycle, which
> seems like a pretty obvious floor to place on a value such as this.
> 
> Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
> ---
>   drivers/nvmem/imx-ocotp.c | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
> index 85a7d0da3abb..5b625d61e433 100644
> --- a/drivers/nvmem/imx-ocotp.c
> +++ b/drivers/nvmem/imx-ocotp.c
> @@ -186,6 +186,8 @@ static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
>   	clk_rate = clk_get_rate(priv->clk);
>   
>   	relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
> +	if (!relax)
> +		relax = 1;

Math here hurts my head. Why is there a -1 above?

How about "relax = DIV_ROUND_UP(clk_rate, 1000000000 / DEF_RELAX);"? 
Rounding up seems safe and it should guarantee that the result is >= 1. 
As far as I understand a value which is slightly larger here shouldn't hurt.

Looking at uboot there DEF_RELAX is moved to the other side but that 
risks overflow at very high ipg rates.

Other chips have similar 66Mhz ipg rates; my guess is that this bug 
affects other chips as well.

--
Regards,
Leonard
Bryan O'Donoghue April 22, 2019, 1:20 p.m. UTC | #2
On 22/04/2019 11:28, Leonard Crestez wrote:
> On 4/19/2019 8:19 PM, Bryan O'Donoghue wrote:
>> The RELAX field of the OCOTP block quote "specifies the time to add to all
>> default timing parameters other than the Tpgm and Trd. It is given in
>> number of ipg_clk periods".
>>
>> On the i.MX8MM the calculation for the RELAX value is turning out to be
>> zero which is not a problem for programming OTP values but, does
>> subsequently mess up reloading the OTP shadow registers.
>>
>> This patch ensures the RELAX field is at least one ipg_clk cycle, which
>> seems like a pretty obvious floor to place on a value such as this.
>>
>> Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
>> ---
>>    drivers/nvmem/imx-ocotp.c | 2 ++
>>    1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
>> index 85a7d0da3abb..5b625d61e433 100644
>> --- a/drivers/nvmem/imx-ocotp.c
>> +++ b/drivers/nvmem/imx-ocotp.c
>> @@ -186,6 +186,8 @@ static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
>>    	clk_rate = clk_get_rate(priv->clk);
>>    
>>    	relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
>> +	if (!relax)
>> +		relax = 1;
> 
> Math here hurts my head. Why is there a -1 above?

I thought of that, in theory it probably works, in practice I'm not so 
sure how it will affect the imx6, where the above code 'just works' 
right now.


> How about "relax = DIV_ROUND_UP(clk_rate, 1000000000 / DEF_RELAX);"?
> Rounding up seems safe and it should guarantee that the result is >= 1.
> As far as I understand a value which is slightly larger here shouldn't hurt.
> 
> Looking at uboot there DEF_RELAX is moved to the other side but that
> risks overflow at very high ipg rates.
> 
> Other chips have similar 66Mhz ipg rates; my guess is that this bug
> affects other chips as well.

Could be. I thought of converting this calculation to the u-boot version 
but... I don't want to break existing code for other users.

I have one i.MX6 board.

It seems safer to me to catch the corner-case for imx8mm.

But, I'm open to further convincing
Bryan O'Donoghue April 22, 2019, 1:37 p.m. UTC | #3
On 22/04/2019 11:28, Leonard Crestez wrote:
> How about "relax = DIV_ROUND_UP(clk_rate, 1000000000 / DEF_RELAX);"?
> Rounding up seems safe and it should guarantee that the result is >= 1.
> As far as I understand a value which is slightly larger here shouldn't hurt.

Actually re-reading your comment I think I'd be on for that.

Dropping the -1 for the RELAX field should be fine for all users - 
because DEF_RELAX != RELAX.

RELAX specifies a number of cycles to do nothing.
DEF_RELAX is a field in a calculation, they are not in fact the same thing.

So it is completely valid to vary RELAX w/r to the DEF_RELAX value we 
have right now and I'm probably being too conservative with the fix-up 
as-is.

---
bod
Leonard Crestez April 22, 2019, 2:35 p.m. UTC | #4
On 4/22/2019 4:37 PM, Bryan O'Donoghue wrote:
> On 22/04/2019 11:28, Leonard Crestez wrote:
>> How about "relax = DIV_ROUND_UP(clk_rate, 1000000000 / DEF_RELAX);"?
>> Rounding up seems safe and it should guarantee that the result is >= 1.
>> As far as I understand a value which is slightly larger here shouldn't hurt.
> 
> Actually re-reading your comment I think I'd be on for that.
> 
> Dropping the -1 for the RELAX field should be fine for all users -
> because DEF_RELAX != RELAX.
> 
> RELAX specifies a number of cycles to do nothing.
> DEF_RELAX is a field in a calculation, they are not in fact the same thing.
> 
> So it is completely valid to vary RELAX w/r to the DEF_RELAX value we
> have right now and I'm probably being too conservative with the fix-up
> as-is.

It seems that all imx6 have an ipg clk of 66Mhz and writes currently 
look like this:

clk_rate=66000000 relax=0 strobe_read=43 strobe_prog=701 timing=002b02bd

As far as I can tell the issue you reported for 8m should affect all imx6.

--
Regards,
Leonard
Bryan O'Donoghue April 22, 2019, 2:56 p.m. UTC | #5
On 22/04/2019 15:35, Leonard Crestez wrote:
> clk_rate=66000000 relax=0 strobe_read=43 strobe_prog=701 timing=002b02bd
> 
> As far as I can tell the issue you reported for 8m should affect all imx6.

OK, I'll add a Fixes in that case
diff mbox series

Patch

diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 85a7d0da3abb..5b625d61e433 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -186,6 +186,8 @@  static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
 	clk_rate = clk_get_rate(priv->clk);
 
 	relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
+	if (!relax)
+		relax = 1;
 	strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
 	strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;