Loading drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +5 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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); Loading drivers/staging/imx-drm/ipu-v3/ipu-common.c +35 −6 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading drivers/staging/imx-drm/ipu-v3/ipu-dc.c +62 −23 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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) Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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) Loading @@ -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); Loading drivers/staging/imx-drm/ipu-v3/ipu-di.c +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +23 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading @@ -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 Loading
drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +5 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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); Loading
drivers/staging/imx-drm/ipu-v3/ipu-common.c +35 −6 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading
drivers/staging/imx-drm/ipu-v3/ipu-dc.c +62 −23 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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) Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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) Loading @@ -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); Loading
drivers/staging/imx-drm/ipu-v3/ipu-di.c +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +23 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; Loading @@ -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