lkml.org 
[lkml]   [2020]   [Jan]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 451/639] nvmem: imx-ocotp: Change TIMING calculation to u-boot algorithm
    Date
    From: Bryan O'Donoghue <pure.logic@nexus-software.ie>

    [ Upstream commit 159dbaf57b2f4f67ecb59b2c87d071e45ed41d7e ]

    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: 0642bac7da42 ("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>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/nvmem/imx-ocotp.c | 36 ++++++++++++++++++++++++++++++++----
    1 file changed, 32 insertions(+), 4 deletions(-)

    diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
    index 04421a73f74aa..09281aca86c29 100644
    --- a/drivers/nvmem/imx-ocotp.c
    +++ b/drivers/nvmem/imx-ocotp.c
    @@ -50,7 +50,9 @@
    #define IMX_OCOTP_BM_CTRL_ERROR 0x00000200
    #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_STROBE_PROG 10000 /* IPG clocks */
    #define IMX_OCOTP_WR_UNLOCK 0x3E770000
    @@ -182,12 +184,38 @@ static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv)
    * fields with timing values to match the current frequency of the
    * ipg_clk. OTP writes will work at maximum bus frequencies as long
    * 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);

    - relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
    - strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
    - strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
    + relax = DIV_ROUND_UP(clk_rate * TIMING_RELAX_NS, 1000000000) - 1;
    + strobe_read = DIV_ROUND_UP(clk_rate * TIMING_STROBE_READ_NS,
    + 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 |= strobe_prog & 0x00000FFF;
    --
    2.20.1


    \
     
     \ /
      Last update: 2020-01-24 12:40    [W:2.128 / U:1.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site