Zynq devcfg occasionally fails (patch)
Thomas Skibo
ThomasSkibo at sbcglobal.net
Wed May 7 19:13:43 UTC 2014
Hello.
I recently started seeing failures programming the Zynq's PL (FPGA)
using the devcfg driver. If the PL happens to be in reset mode already,
the INIT signal isn't asserted fast enough causing a time-out. I've
attached a fix for this as well as a fix to stop WITNESS from complaining.
Thanks,
--Thomas
--
--------
Thomas Skibo
ThomasSkibo at sbcglobal.net
-------------- next part --------------
Index: sys/arm/xilinx/zy7_devcfg.c
===================================================================
--- sys/arm/xilinx/zy7_devcfg.c (revision 265407)
+++ sys/arm/xilinx/zy7_devcfg.c (working copy)
@@ -267,24 +267,35 @@
devcfg_ctl = RD4(sc, ZY7_DEVCFG_CTRL);
+ /* Clear sticky bits and set up INIT signal positive edge interrupt. */
+ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
+ WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE);
+
/* Deassert PROG_B (active low). */
devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B;
WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);
- /* Wait for INIT_B deasserted (active low). */
- tries = 0;
- while ((RD4(sc, ZY7_DEVCFG_STATUS) &
- ZY7_DEVCFG_STATUS_PCFG_INIT) == 0) {
- if (++tries >= 100)
- return (EIO);
- DELAY(5);
+ /*
+ * Wait for INIT to assert. If it is already asserted, we may not get
+ * an edge interrupt so cancel it and continue.
+ */
+ if ((RD4(sc, ZY7_DEVCFG_STATUS) &
+ ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) {
+ /* Already asserted. Cancel interrupt. */
+ WR4(sc, ZY7_DEVCFG_INT_MASK, ~0);
}
-
- /* Reassert PROG_B. */
+ else {
+ /* Wait for positive edge interrupt. */
+ err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i1", hz);
+ if (err != 0)
+ return (err);
+ }
+
+ /* Reassert PROG_B (active low). */
devcfg_ctl &= ~ZY7_DEVCFG_CTRL_PCFG_PROG_B;
WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);
- /* Wait for INIT_B asserted. */
+ /* Wait for INIT deasserted. This happens almost instantly. */
tries = 0;
while ((RD4(sc, ZY7_DEVCFG_STATUS) &
ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) {
@@ -293,7 +304,7 @@
DELAY(5);
}
- /* Clear sticky bits and set up INIT_B positive edge interrupt. */
+ /* Clear sticky bits and set up INIT positive edge interrupt. */
WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE);
@@ -301,11 +312,11 @@
devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B;
WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);
- /* Wait for INIT_B deasserted indicating FPGA internal initialization
- * is complete. This takes much longer than the previous waits for
- * INIT_B transition (on the order of 700us).
+ /*
+ * Wait for INIT asserted indicating FPGA internal initialization
+ * is complete.
*/
- err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7in", hz);
+ err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7i2", hz);
if (err != 0)
return (err);
@@ -404,7 +415,9 @@
/* uiomove the data from user buffer to our dma map. */
segsz = MIN(PAGE_SIZE, uio->uio_resid);
+ DEVCFG_SC_UNLOCK(sc);
err = uiomove(dma_mem, segsz, uio);
+ DEVCFG_SC_LOCK(sc);
if (err != 0)
break;
More information about the freebsd-arm
mailing list