diff options
Diffstat (limited to 'drivers/staging/imx-drm/ipu-v3')
-rw-r--r-- | drivers/staging/imx-drm/ipu-v3/ipu-common.c | 125 | ||||
-rw-r--r-- | drivers/staging/imx-drm/ipu-v3/ipu-di.c | 13 | ||||
-rw-r--r-- | drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c | 22 | ||||
-rw-r--r-- | drivers/staging/imx-drm/ipu-v3/ipu-prv.h | 4 |
4 files changed, 86 insertions, 78 deletions
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c index 0127601c26c7..e35d0bf03c7b 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c @@ -27,6 +27,7 @@ #include <linux/list.h> #include <linux/irq.h> #include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> #include <linux/of_device.h> #include "imx-ipu-v3.h" @@ -799,16 +800,18 @@ err_di_0: static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs) { unsigned long status; - int i, bit, irq_base; + int i, bit, irq; for (i = 0; i < num_regs; i++) { status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i])); status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i])); - irq_base = ipu->irq_start + regs[i] * 32; - for_each_set_bit(bit, &status, 32) - generic_handle_irq(irq_base + bit); + for_each_set_bit(bit, &status, 32) { + irq = irq_linear_revmap(ipu->domain, regs[i] * 32 + bit); + if (irq) + generic_handle_irq(irq); + } } } @@ -838,57 +841,15 @@ static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -static void ipu_ack_irq(struct irq_data *d) -{ - struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq - ipu->irq_start; - - ipu_cm_write(ipu, 1 << (irq % 32), IPU_INT_STAT(irq / 32)); -} - -static void ipu_unmask_irq(struct irq_data *d) -{ - struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq - ipu->irq_start; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&ipu->lock, flags); - - reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32)); - reg |= 1 << (irq % 32); - ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32)); - - spin_unlock_irqrestore(&ipu->lock, flags); -} - -static void ipu_mask_irq(struct irq_data *d) -{ - struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); - unsigned int irq = d->irq - ipu->irq_start; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&ipu->lock, flags); - - reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32)); - reg &= ~(1 << (irq % 32)); - ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32)); - - spin_unlock_irqrestore(&ipu->lock, flags); -} - -static struct irq_chip ipu_irq_chip = { - .name = "IPU", - .irq_ack = ipu_ack_irq, - .irq_mask = ipu_mask_irq, - .irq_unmask = ipu_unmask_irq, -}; - int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, enum ipu_channel_irq irq_type) { - return ipu->irq_start + irq_type + channel->num; + int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num); + + if (!irq) + irq = irq_create_mapping(ipu->domain, irq_type + channel->num); + + return irq; } EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq); @@ -975,18 +936,48 @@ err_register: return ret; } + static int ipu_irq_init(struct ipu_soc *ipu) { - int i; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + unsigned long unused[IPU_NUM_IRQS / 32] = { + 0x400100d0, 0xffe000fd, + 0x400100d0, 0xffe000fd, + 0x400100d0, 0xffe000fd, + 0x4077ffff, 0xffe7e1fd, + 0x23fffffe, 0x8880fff0, + 0xf98fe7d0, 0xfff81fff, + 0x400100d0, 0xffe000fd, + 0x00000000, + }; + int ret, i; + + ipu->domain = irq_domain_add_linear(ipu->dev->of_node, IPU_NUM_IRQS, + &irq_generic_chip_ops, ipu); + if (!ipu->domain) { + dev_err(ipu->dev, "failed to add irq domain\n"); + return -ENODEV; + } - ipu->irq_start = irq_alloc_descs(-1, 0, IPU_NUM_IRQS, 0); - if (ipu->irq_start < 0) - return ipu->irq_start; + ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU", + handle_level_irq, 0, IRQF_VALID, 0); + if (ret < 0) { + dev_err(ipu->dev, "failed to alloc generic irq chips\n"); + irq_domain_remove(ipu->domain); + return ret; + } - for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) { - irq_set_chip_and_handler(i, &ipu_irq_chip, handle_level_irq); - set_irq_flags(i, IRQF_VALID); - irq_set_chip_data(i, ipu); + for (i = 0; i < IPU_NUM_IRQS; i += 32) { + gc = irq_get_domain_generic_chip(ipu->domain, i); + gc->reg_base = ipu->cm_reg; + gc->unused = unused[i / 32]; + ct = gc->chip_types; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->regs.ack = IPU_INT_STAT(i / 32); + ct->regs.mask = IPU_INT_CTRL(i / 32); } irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler); @@ -999,20 +990,22 @@ static int ipu_irq_init(struct ipu_soc *ipu) static void ipu_irq_exit(struct ipu_soc *ipu) { - int i; + int i, irq; irq_set_chained_handler(ipu->irq_err, NULL); irq_set_handler_data(ipu->irq_err, NULL); irq_set_chained_handler(ipu->irq_sync, NULL); irq_set_handler_data(ipu->irq_sync, NULL); - for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) { - set_irq_flags(i, 0); - irq_set_chip(i, NULL); - irq_set_chip_data(i, NULL); + /* TODO: remove irq_domain_generic_chips */ + + for (i = 0; i < IPU_NUM_IRQS; i++) { + irq = irq_linear_revmap(ipu->domain, i); + if (irq) + irq_dispose_mapping(irq); } - irq_free_descs(ipu->irq_start, IPU_NUM_IRQS); + irq_domain_remove(ipu->domain); } static int ipu_probe(struct platform_device *pdev) diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c index 19d777e39d0b..0b6806e2069c 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c @@ -603,7 +603,12 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) vsync_cnt = 3; if (di->id == 1) - vsync_cnt = 6; + /* + * TODO: change only for TVEv2, parallel display + * uses pin 2 / 3 + */ + if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3)) + vsync_cnt = 6; if (sig->Hsync_pol) { if (sig->hsync_pin == 2) @@ -614,11 +619,11 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) di_gen |= DI_GEN_POLARITY_7; } if (sig->Vsync_pol) { - if (sig->hsync_pin == 3) + if (sig->vsync_pin == 3) di_gen |= DI_GEN_POLARITY_3; - else if (sig->hsync_pin == 6) + else if (sig->vsync_pin == 6) di_gen |= DI_GEN_POLARITY_6; - else if (sig->hsync_pin == 8) + else if (sig->vsync_pin == 8) di_gen |= DI_GEN_POLARITY_8; } } diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c index 91821bc30f41..2e97c33b81e7 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c @@ -61,7 +61,7 @@ struct dmfc_channel_data { static const struct dmfc_channel_data dmfcdata[] = { { - .ipu_channel = 23, + .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC, .channel_reg = DMFC_DP_CHAN, .shift = DMFC_DP_CHAN_5B_23, .eot_shift = 20, @@ -73,13 +73,13 @@ static const struct dmfc_channel_data dmfcdata[] = { .eot_shift = 22, .max_fifo_lines = 1, }, { - .ipu_channel = 27, + .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC, .channel_reg = DMFC_DP_CHAN, .shift = DMFC_DP_CHAN_5F_27, .eot_shift = 21, .max_fifo_lines = 2, }, { - .ipu_channel = 28, + .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC, .channel_reg = DMFC_WR_CHAN, .shift = DMFC_WR_CHAN_1_28, .eot_shift = 16, @@ -292,7 +292,7 @@ int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, { struct ipu_dmfc_priv *priv = dmfc->priv; int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second); - int segment = 0, ret = 0; + int segment = -1, ret = 0; dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n", bandwidth_pixel_per_second / 1000000, @@ -307,7 +307,17 @@ int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, goto out; } - segment = dmfc_find_slots(priv, slots); + /* Always allocate at least 128*4 bytes (2 slots) */ + if (slots < 2) + slots = 2; + + /* For the MEM_BG channel, first try to allocate twice the slots */ + if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC) + segment = dmfc_find_slots(priv, slots * 2); + if (segment >= 0) + slots *= 2; + else + segment = dmfc_find_slots(priv, slots); if (segment < 0) { ret = -EBUSY; goto out; @@ -391,7 +401,7 @@ int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, * We have a total bandwidth of clkrate * 4pixel divided * into 8 slots. */ - priv->bandwidth_per_slot = clk_get_rate(ipu_clk) / 8; + priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8; dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n", priv->bandwidth_per_slot / 1000000); diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h index 551802863fd5..4df00501adc2 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h +++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h @@ -110,7 +110,7 @@ struct ipu_soc; #define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32)) #define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32)) -#define IPU_NUM_IRQS (32 * 5) +#define IPU_NUM_IRQS (32 * 15) enum ipu_modules { IPU_CONF_CSI0_EN = (1 << 0), @@ -170,9 +170,9 @@ struct ipu_soc { struct ipuv3_channel channel[64]; - int irq_start; int irq_sync; int irq_err; + struct irq_domain *domain; struct ipu_dc_priv *dc_priv; struct ipu_dp_priv *dp_priv; |