Merge branch 'x86-mds-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / arm / display / komeda / komeda_kms.c
index 47a58ab20434e63b575820bd864045326784f5dc..86f6542afb40d130ca61c0d79b83ac0e4a1142e2 100644 (file)
@@ -13,6 +13,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_irq.h>
 #include <drm/drm_vblank.h>
 
 #include "komeda_dev.h"
@@ -25,18 +26,39 @@ static int komeda_gem_cma_dumb_create(struct drm_file *file,
                                      struct drm_device *dev,
                                      struct drm_mode_create_dumb *args)
 {
-       u32 alignment = 16; /* TODO get alignment from dev */
+       struct komeda_dev *mdev = dev->dev_private;
+       u32 pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
 
-       args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8),
-                           alignment);
+       args->pitch = ALIGN(pitch, mdev->chip.bus_width);
 
        return drm_gem_cma_dumb_create_internal(file, dev, args);
 }
 
+static irqreturn_t komeda_kms_irq_handler(int irq, void *data)
+{
+       struct drm_device *drm = data;
+       struct komeda_dev *mdev = drm->dev_private;
+       struct komeda_kms_dev *kms = to_kdev(drm);
+       struct komeda_events evts;
+       irqreturn_t status;
+       u32 i;
+
+       /* Call into the CHIP to recognize events */
+       memset(&evts, 0, sizeof(evts));
+       status = mdev->funcs->irq_handler(mdev, &evts);
+
+       /* Notify the crtc to handle the events */
+       for (i = 0; i < kms->n_crtcs; i++)
+               komeda_crtc_handle_event(&kms->crtcs[i], &evts);
+
+       return status;
+}
+
 static struct drm_driver komeda_kms_driver = {
        .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
-                          DRIVER_PRIME,
+                          DRIVER_PRIME | DRIVER_HAVE_IRQ,
        .lastclose                      = drm_fb_helper_lastclose,
+       .irq_handler                    = komeda_kms_irq_handler,
        .gem_free_object_unlocked       = drm_gem_cma_free_object,
        .gem_vm_ops                     = &drm_gem_cma_vm_ops,
        .dumb_create                    = komeda_gem_cma_dumb_create,
@@ -78,9 +100,37 @@ static const struct drm_mode_config_helper_funcs komeda_mode_config_helpers = {
        .atomic_commit_tail = komeda_kms_commit_tail,
 };
 
+static int komeda_kms_check(struct drm_device *dev,
+                           struct drm_atomic_state *state)
+{
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_st, *new_crtc_st;
+       int i, err;
+
+       err = drm_atomic_helper_check_modeset(dev, state);
+       if (err)
+               return err;
+
+       /* komeda need to re-calculate resource assumption in every commit
+        * so need to add all affected_planes (even unchanged) to
+        * drm_atomic_state.
+        */
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_st, new_crtc_st, i) {
+               err = drm_atomic_add_affected_planes(state, crtc);
+               if (err)
+                       return err;
+       }
+
+       err = drm_atomic_helper_check_planes(dev, state);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 static const struct drm_mode_config_funcs komeda_mode_config_funcs = {
        .fb_create              = komeda_fb_create,
-       .atomic_check           = drm_atomic_helper_check,
+       .atomic_check           = komeda_kms_check,
        .atomic_commit          = drm_atomic_helper_commit,
 };
 
@@ -144,14 +194,25 @@ struct komeda_kms_dev *komeda_kms_attach(struct komeda_dev *mdev)
 
        drm_mode_config_reset(drm);
 
-       err = drm_dev_register(drm, 0);
+       err = drm_irq_install(drm, mdev->irq);
        if (err)
                goto cleanup_mode_config;
 
+       err = mdev->funcs->enable_irq(mdev);
+       if (err)
+               goto uninstall_irq;
+
+       err = drm_dev_register(drm, 0);
+       if (err)
+               goto uninstall_irq;
+
        return kms;
 
+uninstall_irq:
+       drm_irq_uninstall(drm);
 cleanup_mode_config:
        drm_mode_config_cleanup(drm);
+       komeda_kms_cleanup_private_objs(kms);
 free_kms:
        kfree(kms);
        return ERR_PTR(err);
@@ -162,9 +223,11 @@ void komeda_kms_detach(struct komeda_kms_dev *kms)
        struct drm_device *drm = &kms->base;
        struct komeda_dev *mdev = drm->dev_private;
 
+       mdev->funcs->disable_irq(mdev);
        drm_dev_unregister(drm);
+       drm_irq_uninstall(drm);
        component_unbind_all(mdev->dev, drm);
-       komeda_kms_cleanup_private_objs(mdev);
+       komeda_kms_cleanup_private_objs(kms);
        drm_mode_config_cleanup(drm);
        drm->dev_private = NULL;
        drm_dev_put(drm);