From 7419dc13de9825228d594148d14175c3a58a5d75 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 8 Jul 2015 17:41:56 -0700 Subject: drm/vc4: Add an interrupt handler for the HVS to log errors. This should help in modesetting debugging, for example if we were to program a PV width/height that didn't match the scaler. Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_hvs.c | 56 +++++++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_regs.h | 95 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 4ba37162f39c..6d00440b3e26 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -68,6 +68,34 @@ vc4_hvs_dump_state(struct drm_device *dev) } } +static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) +{ + struct vc4_dev *vc4 = data; + u32 stat = HVS_READ(SCALER_DISPSTAT); + u32 irq_bits = stat & (SCALER_DISPSTAT_IRQSCL | + SCALER_DISPSTAT_IRQDISP0 | + SCALER_DISPSTAT_IRQDISP1 | + SCALER_DISPSTAT_IRQDISP2 | + SCALER_DISPSTAT_IRQSLVWR | + SCALER_DISPSTAT_IRQSLVRD); + irqreturn_t ret = IRQ_NONE; + + if (irq_bits != 0) { + DRM_ERROR("HVS reported error: SCALER_DISPSTAT = 0x%08x\n", + stat); + + /* Mask out whichever of the interrupt enable generated our + * interrupt, so that the error only appears once for this + * type of error + */ + HVS_WRITE(SCALER_DISPCTRL, + HVS_READ(SCALER_DISPCTRL) & ~irq_bits); + ret = IRQ_HANDLED; + } + + return ret; +} + #ifdef CONFIG_DEBUG_FS int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused) { @@ -92,6 +120,7 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm = dev_get_drvdata(master); struct vc4_dev *vc4 = drm->dev_private; struct vc4_hvs *hvs = NULL; + int ret; hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); if (!hvs) @@ -106,6 +135,30 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) hvs->dlist = hvs->regs + SCALER_DLIST_START; vc4->hvs = hvs; + + /* Disable any interrupts set by the firmware. */ + HVS_WRITE(SCALER_DISPCTRL, SCALER_DISPCTRL_ENABLE); + /* Clear any previous interrupts. */ + HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQSCL); + + ret = devm_request_irq(dev, platform_get_irq(pdev, 0), + vc4_hvs_irq_handler, 0, "vc4 hvs", vc4); + if (ret) + return ret; + + /* Turn on a bunch of interrupts for catching HW setup errors. */ + HVS_WRITE(SCALER_DISPCTRL, + SCALER_DISPCTRL_ENABLE | + SCALER_DISPCTRL_DSP0EISLUR | + SCALER_DISPCTRL_DSP1EISLUR | + SCALER_DISPCTRL_DSP2EISLUR | + SCALER_DISPCTRL_SLVRDEIRQ | + SCALER_DISPCTRL_SLVWREIRQ | + SCALER_DISPCTRL_DMAEIRQ | + SCALER_DISPCTRL_DISP0EIRQ | + SCALER_DISPCTRL_DISP1EIRQ | + SCALER_DISPCTRL_DISP2EIRQ); + return 0; } @@ -115,6 +168,9 @@ static void vc4_hvs_unbind(struct device *dev, struct device *master, struct drm_device *drm = dev_get_drvdata(master); struct vc4_dev *vc4 = drm->dev_private; + HVS_WRITE(SCALER_DISPCTRL, SCALER_DISPCTRL_ENABLE); + HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQSCL); + vc4->hvs = NULL; } diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h index ff6197cde4f4..2282804ae101 100644 --- a/drivers/gpu/drm/vc4/vc4_regs.h +++ b/drivers/gpu/drm/vc4/vc4_regs.h @@ -233,8 +233,103 @@ #define SCALER_DISPCTRL 0x00000000 /* Global register for clock gating the HVS */ # define SCALER_DISPCTRL_ENABLE (1 << 31) +# define SCALER_DISPCTRL_DSP2EISLUR (1 << 15) +# define SCALER_DISPCTRL_DSP1EISLUR (1 << 14) +/* + * Enables Display 0 short line and underrun contribution to + * SCALER_DISPSTAT_IRQDISP0. Note that short frame contributions are + * always enabled. + */ +# define SCALER_DISPCTRL_DSP0EISLUR (1 << 13) +# define SCALER_DISPCTRL_DSP2EIEOLN (1 << 12) +# define SCALER_DISPCTRL_DSP2EIEOF (1 << 11) +# define SCALER_DISPCTRL_DSP1EIEOLN (1 << 10) +# define SCALER_DISPCTRL_DSP1EIEOF (1 << 9) +/* + * Enables Display 0 end-of-line-N contribution to + * SCALER_DISPSTAT_IRQDISP0 + */ +# define SCALER_DISPCTRL_DSP0EIEOLN (1 << 8) +/* Enables Display 0 EOF contribution to SCALER_DISPSTAT_IRQDISP0 */ +# define SCALER_DISPCTRL_DSP0EIEOF (1 << 7) + +# define SCALER_DISPCTRL_SLVRDEIRQ (1 << 6) +# define SCALER_DISPCTRL_SLVWREIRQ (1 << 5) +# define SCALER_DISPCTRL_DMAEIRQ (1 << 4) +# define SCALER_DISPCTRL_DISP2EIRQ (1 << 3) +# define SCALER_DISPCTRL_DISP1EIRQ (1 << 2) +/* + * Enables interrupt generation on the enabled EOF/EOLN/EISLUR + * bits and short frames.. + */ +# define SCALER_DISPCTRL_DISP0EIRQ (1 << 1) +/* Enables interrupt generation on scaler profiler interrupt. */ +# define SCALER_DISPCTRL_SCLEIRQ (1 << 0) #define SCALER_DISPSTAT 0x00000004 +# define SCALER_DISPSTAT_COBLOW2 (1 << 29) +# define SCALER_DISPSTAT_EOLN2 (1 << 28) +# define SCALER_DISPSTAT_ESFRAME2 (1 << 27) +# define SCALER_DISPSTAT_ESLINE2 (1 << 26) +# define SCALER_DISPSTAT_EUFLOW2 (1 << 25) +# define SCALER_DISPSTAT_EOF2 (1 << 24) + +# define SCALER_DISPSTAT_COBLOW1 (1 << 21) +# define SCALER_DISPSTAT_EOLN1 (1 << 20) +# define SCALER_DISPSTAT_ESFRAME1 (1 << 19) +# define SCALER_DISPSTAT_ESLINE1 (1 << 18) +# define SCALER_DISPSTAT_EUFLOW1 (1 << 17) +# define SCALER_DISPSTAT_EOF1 (1 << 16) + +# define SCALER_DISPSTAT_RESP_MASK VC4_MASK(15, 14) +# define SCALER_DISPSTAT_RESP_SHIFT 14 +# define SCALER_DISPSTAT_RESP_OKAY 0 +# define SCALER_DISPSTAT_RESP_EXOKAY 1 +# define SCALER_DISPSTAT_RESP_SLVERR 2 +# define SCALER_DISPSTAT_RESP_DECERR 3 + +# define SCALER_DISPSTAT_COBLOW0 (1 << 13) +/* Set when the DISPEOLN line is done compositing. */ +# define SCALER_DISPSTAT_EOLN0 (1 << 12) +/* + * Set when VSTART is seen but there are still pixels in the current + * output line. + */ +# define SCALER_DISPSTAT_ESFRAME0 (1 << 11) +/* + * Set when HSTART is seen but there are still pixels in the current + * output line. + */ +# define SCALER_DISPSTAT_ESLINE0 (1 << 10) +/* + * Set when the the downstream tries to read from the display FIFO + * while it's empty. + */ +# define SCALER_DISPSTAT_EUFLOW0 (1 << 9) +/* Set when the display mode changes from RUN to EOF */ +# define SCALER_DISPSTAT_EOF0 (1 << 8) + +/* Set on AXI invalid DMA ID error. */ +# define SCALER_DISPSTAT_DMA_ERROR (1 << 7) +/* Set on AXI slave read decode error */ +# define SCALER_DISPSTAT_IRQSLVRD (1 << 6) +/* Set on AXI slave write decode error */ +# define SCALER_DISPSTAT_IRQSLVWR (1 << 5) +/* + * Set when SCALER_DISPSTAT_DMA_ERROR is set, or + * SCALER_DISPSTAT_RESP_ERROR is not SCALER_DISPSTAT_RESP_OKAY. + */ +# define SCALER_DISPSTAT_IRQDMA (1 << 4) +# define SCALER_DISPSTAT_IRQDISP2 (1 << 3) +# define SCALER_DISPSTAT_IRQDISP1 (1 << 2) +/* + * Set when any of the EOF/EOLN/ESFRAME/ESLINE bits are set and their + * corresponding interrupt bit is enabled in DISPCTRL. + */ +# define SCALER_DISPSTAT_IRQDISP0 (1 << 1) +/* On read, the profiler interrupt. On write, clear *all* interrupt bits. */ +# define SCALER_DISPSTAT_IRQSCL (1 << 0) + #define SCALER_DISPID 0x00000008 #define SCALER_DISPECTRL 0x0000000c #define SCALER_DISPPROF 0x00000010 -- cgit v1.2.1