mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-03 17:40:04 +00:00
nvmem: imx-ocotp: Change TIMING calculation to u-boot algorithm
The RELAX field of the OCOTP block is turning out as a zero on i.MX8MM.
This messes up the subsequent re-load of the fuse shadow registers.
After some discussion with people @ NXP its clear we have missed a trick
here in Linux.
The OCOTP fuse programming time has a physical minimum 'burn time' that is
not related to the ipg_clk.
We need to define the RELAX, STROBE_READ and STROBE_PROG fields in terms of
desired timings to allow for the burn-in to safely complete. Right now only
the RELAX field is calculated in terms of an absolute time and we are
ending up with a value of zero.
This patch inherits the u-boot timings for the OCOTP_TIMING calculation on
the i.MX6 and i.MX8. Those timings are known to work and critically specify
values such as STROBE_PROG as a minimum timing.
Fixes: 0642bac7da
("nvmem: imx-ocotp: add write support")
Signed-off-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
Suggested-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Leonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
0493c4792b
commit
159dbaf57b
1 changed files with 32 additions and 4 deletions
|
@ -44,7 +44,9 @@
|
||||||
#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
|
#define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
|
||||||
#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
|
#define IMX_OCOTP_BM_CTRL_REL_SHADOWS 0x00000400
|
||||||
|
|
||||||
#define DEF_RELAX 20 /* > 16.5ns */
|
#define TIMING_STROBE_PROG_US 10 /* Min time to blow a fuse */
|
||||||
|
#define TIMING_STROBE_READ_NS 37 /* Min time before read */
|
||||||
|
#define TIMING_RELAX_NS 17
|
||||||
#define DEF_FSOURCE 1001 /* > 1000 ns */
|
#define DEF_FSOURCE 1001 /* > 1000 ns */
|
||||||
#define DEF_STROBE_PROG 10000 /* IPG clocks */
|
#define DEF_STROBE_PROG 10000 /* IPG clocks */
|
||||||
#define IMX_OCOTP_WR_UNLOCK 0x3E770000
|
#define IMX_OCOTP_WR_UNLOCK 0x3E770000
|
||||||
|
@ -176,12 +178,38 @@ static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
|
||||||
* fields with timing values to match the current frequency of the
|
* fields with timing values to match the current frequency of the
|
||||||
* ipg_clk. OTP writes will work at maximum bus frequencies as long
|
* ipg_clk. OTP writes will work at maximum bus frequencies as long
|
||||||
* as the HW_OCOTP_TIMING parameters are set correctly.
|
* as the HW_OCOTP_TIMING parameters are set correctly.
|
||||||
|
*
|
||||||
|
* Note: there are minimum timings required to ensure an OTP fuse burns
|
||||||
|
* correctly that are independent of the ipg_clk. Those values are not
|
||||||
|
* formally documented anywhere however, working from the minimum
|
||||||
|
* timings given in u-boot we can say:
|
||||||
|
*
|
||||||
|
* - Minimum STROBE_PROG time is 10 microseconds. Intuitively 10
|
||||||
|
* microseconds feels about right as representative of a minimum time
|
||||||
|
* to physically burn out a fuse.
|
||||||
|
*
|
||||||
|
* - Minimum STROBE_READ i.e. the time to wait post OTP fuse burn before
|
||||||
|
* performing another read is 37 nanoseconds
|
||||||
|
*
|
||||||
|
* - Minimum RELAX timing is 17 nanoseconds. This final RELAX minimum
|
||||||
|
* timing is not entirely clear the documentation says "This
|
||||||
|
* count value 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." where Tpgm and Trd refer to STROBE_PROG
|
||||||
|
* and STROBE_READ respectively. What the other timing parameters
|
||||||
|
* are though, is not specified. Experience shows a zero RELAX
|
||||||
|
* value will mess up a re-load of the shadow registers post OTP
|
||||||
|
* burn.
|
||||||
*/
|
*/
|
||||||
clk_rate = clk_get_rate(priv->clk);
|
clk_rate = clk_get_rate(priv->clk);
|
||||||
|
|
||||||
relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
|
relax = DIV_ROUND_UP(clk_rate * TIMING_RELAX_NS, 1000000000) - 1;
|
||||||
strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
|
strobe_read = DIV_ROUND_UP(clk_rate * TIMING_STROBE_READ_NS,
|
||||||
strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
|
1000000000);
|
||||||
|
strobe_read += 2 * (relax + 1) - 1;
|
||||||
|
strobe_prog = DIV_ROUND_CLOSEST(clk_rate * TIMING_STROBE_PROG_US,
|
||||||
|
1000000);
|
||||||
|
strobe_prog += 2 * (relax + 1) - 1;
|
||||||
|
|
||||||
timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000;
|
timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000;
|
||||||
timing |= strobe_prog & 0x00000FFF;
|
timing |= strobe_prog & 0x00000FFF;
|
||||||
|
|
Loading…
Reference in a new issue