drm/nouveau/disp: audit and version display classes
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / ipu-v3 / ipu-common.c
index 2aecc474c4783f8c98b4ba6b2838e712c1c715c7..04e7b2eafbdd7b127fd540873cd334693f4f4d40 100644 (file)
@@ -661,6 +661,39 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
 }
 EXPORT_SYMBOL_GPL(ipu_module_disable);
 
+int ipu_csi_enable(struct ipu_soc *ipu, int csi)
+{
+       return ipu_module_enable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_enable);
+
+int ipu_csi_disable(struct ipu_soc *ipu, int csi)
+{
+       return ipu_module_disable(ipu, csi ? IPU_CONF_CSI1_EN : IPU_CONF_CSI0_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_disable);
+
+int ipu_smfc_enable(struct ipu_soc *ipu)
+{
+       return ipu_module_enable(ipu, IPU_CONF_SMFC_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_enable);
+
+int ipu_smfc_disable(struct ipu_soc *ipu)
+{
+       return ipu_module_disable(ipu, IPU_CONF_SMFC_EN);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_disable);
+
+int ipu_idmac_get_current_buffer(struct ipuv3_channel *channel)
+{
+       struct ipu_soc *ipu = channel->ipu;
+       unsigned int chno = channel->num;
+
+       return (ipu_cm_read(ipu, IPU_CHA_CUR_BUF(chno)) & idma_mask(chno)) ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_get_current_buffer);
+
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
 {
        struct ipu_soc *ipu = channel->ipu;
@@ -697,6 +730,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 +753,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;
@@ -909,7 +964,8 @@ static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
                status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i]));
 
                for_each_set_bit(bit, &status, 32) {
-                       irq = irq_linear_revmap(ipu->domain, regs[i] * 32 + bit);
+                       irq = irq_linear_revmap(ipu->domain,
+                                               regs[i] * 32 + bit);
                        if (irq)
                                generic_handle_irq(irq);
                }
@@ -942,15 +998,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);
 
@@ -981,6 +1044,7 @@ static void platform_device_unregister_children(struct platform_device *pdev)
 struct ipu_platform_reg {
        struct ipu_client_platformdata pdata;
        const char *name;
+       int reg_offset;
 };
 
 static const struct ipu_platform_reg client_reg[] = {
@@ -1002,13 +1066,29 @@ static const struct ipu_platform_reg client_reg[] = {
                        .dma[1] = -EINVAL,
                },
                .name = "imx-ipuv3-crtc",
+       }, {
+               .pdata = {
+                       .csi = 0,
+                       .dma[0] = IPUV3_CHANNEL_CSI0,
+                       .dma[1] = -EINVAL,
+               },
+               .reg_offset = IPU_CM_CSI0_REG_OFS,
+               .name = "imx-ipuv3-camera",
+       }, {
+               .pdata = {
+                       .csi = 1,
+                       .dma[0] = IPUV3_CHANNEL_CSI1,
+                       .dma[1] = -EINVAL,
+               },
+               .reg_offset = IPU_CM_CSI1_REG_OFS,
+               .name = "imx-ipuv3-camera",
        },
 };
 
 static DEFINE_MUTEX(ipu_client_id_mutex);
 static int ipu_client_id;
 
-static int ipu_add_client_devices(struct ipu_soc *ipu)
+static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
 {
        struct device *dev = ipu->dev;
        unsigned i;
@@ -1022,9 +1102,19 @@ static int ipu_add_client_devices(struct ipu_soc *ipu)
        for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
                const struct ipu_platform_reg *reg = &client_reg[i];
                struct platform_device *pdev;
-
-               pdev = platform_device_register_data(dev, reg->name,
-                       id++, &reg->pdata, sizeof(reg->pdata));
+               struct resource res;
+
+               if (reg->reg_offset) {
+                       memset(&res, 0, sizeof(res));
+                       res.flags = IORESOURCE_MEM;
+                       res.start = ipu_base + ipu->devtype->cm_ofs + reg->reg_offset;
+                       res.end = res.start + PAGE_SIZE - 1;
+                       pdev = platform_device_register_resndata(dev, reg->name,
+                               id++, &res, 1, &reg->pdata, sizeof(reg->pdata));
+               } else {
+                       pdev = platform_device_register_data(dev, reg->name,
+                               id++, &reg->pdata, sizeof(reg->pdata));
+               }
 
                if (IS_ERR(pdev))
                        goto err_register;
@@ -1063,7 +1153,8 @@ static int ipu_irq_init(struct ipu_soc *ipu)
        }
 
        ret = irq_alloc_domain_generic_chips(ipu->domain, 32, 1, "IPU",
-                                            handle_level_irq, 0, IRQF_VALID, 0);
+                                            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);
@@ -1220,7 +1311,7 @@ static int ipu_probe(struct platform_device *pdev)
        if (ret)
                goto failed_submodules_init;
 
-       ret = ipu_add_client_devices(ipu);
+       ret = ipu_add_client_devices(ipu, ipu_base);
        if (ret) {
                dev_err(&pdev->dev, "adding client devices failed with %d\n",
                                ret);