These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / ipu-v3 / ipu-common.c
index 67bab5c..a0e28f3 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
 #include <linux/of_device.h>
+#include <linux/of_graph.h>
 
 #include <drm/drm_fourcc.h>
 
@@ -57,10 +58,15 @@ EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
 {
        switch (drm_fourcc) {
+       case DRM_FORMAT_ARGB1555:
+       case DRM_FORMAT_ABGR1555:
+       case DRM_FORMAT_RGBA5551:
+       case DRM_FORMAT_BGRA5551:
        case DRM_FORMAT_RGB565:
        case DRM_FORMAT_BGR565:
        case DRM_FORMAT_RGB888:
        case DRM_FORMAT_BGR888:
+       case DRM_FORMAT_ARGB4444:
        case DRM_FORMAT_XRGB8888:
        case DRM_FORMAT_XBGR8888:
        case DRM_FORMAT_RGBX8888:
@@ -912,11 +918,11 @@ static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs)
        }
 }
 
-static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc)
+static void ipu_irq_handler(struct irq_desc *desc)
 {
        struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
        const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
-       struct irq_chip *chip = irq_get_chip(irq);
 
        chained_irq_enter(chip, desc);
 
@@ -925,11 +931,11 @@ static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc)
+static void ipu_err_irq_handler(struct irq_desc *desc)
 {
        struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
        const int int_reg[] = { 4, 5, 8, 9};
-       struct irq_chip *chip = irq_get_chip(irq);
 
        chained_irq_enter(chip, desc);
 
@@ -988,11 +994,25 @@ 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;
 };
 
+/* These must be in the order of the corresponding device tree port nodes */
 static const struct ipu_platform_reg client_reg[] = {
        {
+               .pdata = {
+                       .csi = 0,
+                       .dma[0] = IPUV3_CHANNEL_CSI0,
+                       .dma[1] = -EINVAL,
+               },
+               .name = "imx-ipuv3-camera",
+       }, {
+               .pdata = {
+                       .csi = 1,
+                       .dma[0] = IPUV3_CHANNEL_CSI1,
+                       .dma[1] = -EINVAL,
+               },
+               .name = "imx-ipuv3-camera",
+       }, {
                .pdata = {
                        .di = 0,
                        .dc = 5,
@@ -1010,22 +1030,6 @@ 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",
        },
 };
 
@@ -1046,22 +1050,33 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
        for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
                const struct ipu_platform_reg *reg = &client_reg[i];
                struct platform_device *pdev;
-               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));
+               struct device_node *of_node;
+
+               /* Associate subdevice with the corresponding port node */
+               of_node = of_graph_get_port_by_id(dev->of_node, i);
+               if (!of_node) {
+                       dev_info(dev,
+                                "no port@%d node in %s, not using %s%d\n",
+                                i, dev->of_node->full_name,
+                                (i / 2) ? "DI" : "CSI", i % 2);
+                       continue;
+               }
+
+               pdev = platform_device_alloc(reg->name, id++);
+               if (!pdev) {
+                       ret = -ENOMEM;
+                       goto err_register;
                }
 
-               if (IS_ERR(pdev)) {
-                       ret = PTR_ERR(pdev);
+               pdev->dev.of_node = of_node;
+               pdev->dev.parent = dev;
+
+               ret = platform_device_add_data(pdev, &reg->pdata,
+                                              sizeof(reg->pdata));
+               if (!ret)
+                       ret = platform_device_add(pdev);
+               if (ret) {
+                       platform_device_put(pdev);
                        goto err_register;
                }
        }
@@ -1099,14 +1114,16 @@ 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, 0, 0);
        if (ret < 0) {
                dev_err(ipu->dev, "failed to alloc generic irq chips\n");
                irq_domain_remove(ipu->domain);
                return ret;
        }
 
+       for (i = 0; i < IPU_NUM_IRQS; i += 32)
+               ipu_cm_write(ipu, 0, IPU_INT_CTRL(i / 32));
+
        for (i = 0; i < IPU_NUM_IRQS; i += 32) {
                gc = irq_get_domain_generic_chip(ipu->domain, i);
                gc->reg_base = ipu->cm_reg;
@@ -1119,10 +1136,9 @@ static int ipu_irq_init(struct ipu_soc *ipu)
                ct->regs.mask = IPU_INT_CTRL(i / 32);
        }
 
-       irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler);
-       irq_set_handler_data(ipu->irq_sync, ipu);
-       irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler);
-       irq_set_handler_data(ipu->irq_err, ipu);
+       irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu);
+       irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler,
+                                        ipu);
 
        return 0;
 }
@@ -1131,10 +1147,8 @@ static void ipu_irq_exit(struct ipu_soc *ipu)
 {
        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);
+       irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL);
+       irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL);
 
        /* TODO: remove irq_domain_generic_chips */