Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4784756 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge branch 'imx-drm-fixes' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into staging-next

imx-drm fixes from Russell
parents a3476ac6 1e6d486b
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ enum ipu_channel_irq {
	IPU_IRQ_EOS = 192,
};

int ipu_map_irq(struct ipu_soc *ipu, int irq);
int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
		enum ipu_channel_irq irq);

@@ -114,8 +115,10 @@ struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel);
void ipu_dc_put(struct ipu_dc *dc);
int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
		u32 pixel_fmt, u32 width);
void ipu_dc_enable(struct ipu_soc *ipu);
void ipu_dc_enable_channel(struct ipu_dc *dc);
void ipu_dc_disable_channel(struct ipu_dc *dc);
void ipu_dc_disable(struct ipu_soc *ipu);

/*
 * IPU Display Interface (di) functions
@@ -152,8 +155,10 @@ void ipu_dmfc_put(struct dmfc_channel *dmfc);

struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow);
void ipu_dp_put(struct ipu_dp *);
int ipu_dp_enable(struct ipu_soc *ipu);
int ipu_dp_enable_channel(struct ipu_dp *dp);
void ipu_dp_disable_channel(struct ipu_dp *dp);
void ipu_dp_disable(struct ipu_soc *ipu);
int ipu_dp_setup_channel(struct ipu_dp *dp,
		enum ipu_color_space in, enum ipu_color_space out);
int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
+35 −6
Original line number Diff line number Diff line
@@ -697,6 +697,12 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
}
EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);

bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
{
	return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
}
EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);

int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
{
	struct ipu_soc *ipu = channel->ipu;
@@ -714,6 +720,22 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
}
EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);

int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms)
{
	unsigned long timeout;

	timeout = jiffies + msecs_to_jiffies(ms);
	ipu_cm_write(ipu, BIT(irq % 32), IPU_INT_STAT(irq / 32));
	while (!(ipu_cm_read(ipu, IPU_INT_STAT(irq / 32) & BIT(irq % 32)))) {
		if (time_after(jiffies, timeout))
			return -ETIMEDOUT;
		cpu_relax();
	}

	return 0;
}
EXPORT_SYMBOL_GPL(ipu_wait_interrupt);

int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
{
	struct ipu_soc *ipu = channel->ipu;
@@ -934,15 +956,22 @@ static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc)
	chained_irq_exit(chip, desc);
}

int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
		enum ipu_channel_irq irq_type)
int ipu_map_irq(struct ipu_soc *ipu, int irq)
{
	int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num);
	int virq;

	if (!irq)
		irq = irq_create_mapping(ipu->domain, irq_type + channel->num);
	virq = irq_linear_revmap(ipu->domain, irq);
	if (!virq)
		virq = irq_create_mapping(ipu->domain, irq);

	return irq;
	return virq;
}
EXPORT_SYMBOL_GPL(ipu_map_irq);

int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
		enum ipu_channel_irq irq_type)
{
	return ipu_map_irq(ipu, irq_type + channel->num);
}
EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);

+62 −23
Original line number Diff line number Diff line
@@ -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"
@@ -111,6 +112,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)
@@ -223,12 +227,16 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
	writel(0x0, dc->base + DC_WR_CH_ADDR);
	writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));

	ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);

	return 0;
}
EXPORT_SYMBOL_GPL(ipu_dc_init_sync);

void ipu_dc_enable(struct ipu_soc *ipu)
{
	ipu_module_enable(ipu, IPU_CONF_DC_EN);
}
EXPORT_SYMBOL_GPL(ipu_dc_enable);

void ipu_dc_enable_channel(struct ipu_dc *dc)
{
	int di;
@@ -242,41 +250,55 @@ 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);

	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;
	}
	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");

		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);

void ipu_dc_disable(struct ipu_soc *ipu)
{
	ipu_module_disable(ipu, IPU_CONF_DC_EN);
}
EXPORT_SYMBOL_GPL(ipu_dc_disable);

static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
		int byte_num, int offset, int mask)
{
@@ -343,7 +365,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)
@@ -364,6 +386,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);
+1 −1
Original line number Diff line number Diff line
@@ -595,7 +595,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
		}
	}

	if (!sig->clk_pol)
	if (sig->clk_pol)
		di_gen |= DI_GEN_POLARITY_DISP_CLK;

	ipu_di_write(di, di_gen, DI_GENERAL);
+23 −2
Original line number Diff line number Diff line
@@ -28,7 +28,12 @@
#define DMFC_GENERAL1		0x0014
#define DMFC_GENERAL2		0x0018
#define DMFC_IC_CTRL		0x001c
#define DMFC_STAT		0x0020
#define DMFC_WR_CHAN_ALT	0x0020
#define DMFC_WR_CHAN_DEF_ALT	0x0024
#define DMFC_DP_CHAN_ALT	0x0028
#define DMFC_DP_CHAN_DEF_ALT	0x002c
#define DMFC_GENERAL1_ALT	0x0030
#define DMFC_STAT		0x0034

#define DMFC_WR_CHAN_1_28		0
#define DMFC_WR_CHAN_2_41		8
@@ -133,6 +138,20 @@ int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
}
EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);

static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);

	while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) {
		if (time_after(jiffies, timeout)) {
			dev_warn(priv->dev,
				 "Timeout waiting for DMFC FIFOs to clear\n");
			break;
		}
		cpu_relax();
	}
}

void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
{
	struct ipu_dmfc_priv *priv = dmfc->priv;
@@ -141,8 +160,10 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)

	priv->use_count--;

	if (!priv->use_count)
	if (!priv->use_count) {
		ipu_dmfc_wait_fifos(priv);
		ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
	}

	if (priv->use_count < 0)
		priv->use_count = 0;
Loading