mirror of https://gitee.com/openkylin/linux.git
imx-drm: ipu-dc: wait for DC_FC_1 / DP_SF_END interrupt
Wait for the DC Frame Complete or DP Sync Flow End interrupts before disabling DC channels. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
47348661c4
commit
1dee9a9e53
|
@ -18,6 +18,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "../imx-drm.h"
|
||||
|
@ -110,6 +111,9 @@ struct ipu_dc_priv {
|
|||
struct device *dev;
|
||||
struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
|
||||
struct mutex mutex;
|
||||
struct completion comp;
|
||||
int dc_irq;
|
||||
int dp_irq;
|
||||
};
|
||||
|
||||
static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
|
||||
|
@ -239,38 +243,46 @@ void ipu_dc_enable_channel(struct ipu_dc *dc)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
|
||||
|
||||
static irqreturn_t dc_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct ipu_dc *dc = dev_id;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(dc->base + DC_WR_CH_CONF);
|
||||
reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
|
||||
writel(reg, dc->base + DC_WR_CH_CONF);
|
||||
|
||||
/* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */
|
||||
|
||||
complete(&dc->priv->comp);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void ipu_dc_disable_channel(struct ipu_dc *dc)
|
||||
{
|
||||
struct ipu_dc_priv *priv = dc->priv;
|
||||
int irq, ret;
|
||||
u32 val;
|
||||
int irq = 0, timeout = 50;
|
||||
|
||||
/* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */
|
||||
if (dc->chno == 1)
|
||||
irq = IPU_IRQ_DC_FC_1;
|
||||
irq = priv->dc_irq;
|
||||
else if (dc->chno == 5)
|
||||
irq = IPU_IRQ_DP_SF_END;
|
||||
irq = priv->dp_irq;
|
||||
else
|
||||
return;
|
||||
|
||||
/* should wait for the interrupt here */
|
||||
mdelay(50);
|
||||
init_completion(&priv->comp);
|
||||
enable_irq(irq);
|
||||
ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50));
|
||||
disable_irq(irq);
|
||||
if (ret <= 0) {
|
||||
dev_warn(priv->dev, "DC stop timeout after 50 ms\n");
|
||||
|
||||
if (dc->di == 0)
|
||||
val = 0x00000002;
|
||||
else
|
||||
val = 0x00000020;
|
||||
|
||||
/* Wait for DC triple buffer to empty */
|
||||
while ((readl(priv->dc_reg + DC_STAT) & val) != val) {
|
||||
usleep_range(2000, 20000);
|
||||
timeout -= 2;
|
||||
if (timeout <= 0)
|
||||
break;
|
||||
val = readl(dc->base + DC_WR_CH_CONF);
|
||||
val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
|
||||
writel(val, dc->base + DC_WR_CH_CONF);
|
||||
}
|
||||
|
||||
val = readl(dc->base + DC_WR_CH_CONF);
|
||||
val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
|
||||
writel(val, dc->base + DC_WR_CH_CONF);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
|
||||
|
||||
|
@ -340,7 +352,7 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
|
|||
struct ipu_dc_priv *priv;
|
||||
static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
|
||||
0x78, 0, 0x94, 0xb4};
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
|
@ -361,6 +373,23 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
|
|||
priv->channels[i].base = priv->dc_reg + channel_offsets[i];
|
||||
}
|
||||
|
||||
priv->dc_irq = ipu_map_irq(ipu, IPU_IRQ_DC_FC_1);
|
||||
if (!priv->dc_irq)
|
||||
return -EINVAL;
|
||||
ret = devm_request_irq(dev, priv->dc_irq, dc_irq_handler, 0, NULL,
|
||||
&priv->channels[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
disable_irq(priv->dc_irq);
|
||||
priv->dp_irq = ipu_map_irq(ipu, IPU_IRQ_DP_SF_END);
|
||||
if (!priv->dp_irq)
|
||||
return -EINVAL;
|
||||
ret = devm_request_irq(dev, priv->dp_irq, dc_irq_handler, 0, NULL,
|
||||
&priv->channels[5]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
disable_irq(priv->dp_irq);
|
||||
|
||||
writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
|
||||
DC_WR_CH_CONF_PROG_DI_ID,
|
||||
priv->channels[1].base + DC_WR_CH_CONF);
|
||||
|
|
Loading…
Reference in New Issue