X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=drivers%2Fmisc%2Fmxc_ocotp.c;h=f468d9d5839fdf0ec68418f890235468f26b1378;hp=3de1245699626aa4429dba9462ef398ef77bd63c;hb=5c00621c4e675853218bcf8a769c8f7ef83f40a9;hpb=3be2bdf5dc69b3142c1162a59bc67191c9077567 diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c index 3de1245699..f468d9d583 100644 --- a/drivers/misc/mxc_ocotp.c +++ b/drivers/misc/mxc_ocotp.c @@ -42,11 +42,22 @@ #define BF(value, field) (((value) << BO_##field) & BM_##field) #define WRITE_POSTAMBLE_US 2 +#define MXC_OTP_BUSY_TIMEOUT 1000 -static void wait_busy(struct ocotp_regs *regs, unsigned int delay_us) +static bool wait_busy(struct ocotp_regs *regs, unsigned int delay_us) { - while (readl(®s->ctrl) & BM_CTRL_BUSY) + unsigned long start; + u32 reg; + + start = get_timer_masked(); + while ((reg = readl(®s->ctrl)) & BM_CTRL_BUSY) { udelay(delay_us); + if (get_timer(start) > MXC_OTP_BUSY_TIMEOUT) + break; + } + if (!(reg & BM_CTRL_BUSY)) + return 1; + return !(readl(®s->ctrl) & BM_CTRL_BUSY); } static void clear_error(struct ocotp_regs *regs) @@ -60,7 +71,7 @@ static int prepare_access(struct ocotp_regs **regs, u32 bank, u32 word, *regs = (struct ocotp_regs *)OCOTP_BASE_ADDR; if (bank >= ARRAY_SIZE((*regs)->bank) || - word >= ARRAY_SIZE((*regs)->bank[0].fuse_regs) >> 2 || + word >= ARRAY_SIZE((*regs)->bank[0].fuse_regs) || !assert) { printf("mxc_ocotp %s(): Invalid argument\n", caller); return -EINVAL; @@ -68,8 +79,10 @@ static int prepare_access(struct ocotp_regs **regs, u32 bank, u32 word, enable_ocotp_clk(1); - wait_busy(*regs, 1); - clear_error(*regs); + if (wait_busy(*regs, 1)) + clear_error(*regs); + else + return -ETIMEDOUT; return 0; } @@ -80,7 +93,6 @@ static int finish_access(struct ocotp_regs *regs, const char *caller) err = !!(readl(®s->ctrl) & BM_CTRL_ERROR); clear_error(regs); - enable_ocotp_clk(0); if (err) { @@ -122,8 +134,8 @@ static void set_timing(struct ocotp_regs *regs) relax = DIV_ROUND_UP(ipg_clk * BV_TIMING_RELAX_NS, 1000000000) - 1; strobe_read = DIV_ROUND_UP(ipg_clk * BV_TIMING_STROBE_READ_NS, 1000000000) + 2 * (relax + 1) - 1; - strobe_prog = DIV_ROUND(ipg_clk * BV_TIMING_STROBE_PROG_US, 1000000) + - 2 * (relax + 1) - 1; + strobe_prog = DIV_ROUND_CLOSEST(ipg_clk * BV_TIMING_STROBE_PROG_US, + 1000000) + 2 * (relax + 1) - 1; timing = BF(strobe_read, TIMING_STROBE_READ) | BF(relax, TIMING_RELAX) | @@ -156,8 +168,10 @@ int fuse_sense(u32 bank, u32 word, u32 *val) setup_direct_access(regs, bank, word, false); writel(BM_READ_CTRL_READ_FUSE, ®s->read_ctrl); - wait_busy(regs, 1); - *val = readl(®s->read_fuse_data); + if (wait_busy(regs, 1)) + *val = readl(®s->read_fuse_data); + else + *val = ~0; return finish_access(regs, __func__); }