drm/nouveau/core: rework event interface
[pandora-kernel.git] / drivers / gpu / drm / nouveau / nouveau_display.c
index 47ad742..ff43b41 100644 (file)
 #include <engine/disp.h>
 
 #include <core/class.h>
+#include <nvif/event.h>
 
 static int
-nouveau_display_vblank_handler(void *data, u32 type, int head)
+nouveau_display_vblank_handler(struct nvkm_notify *notify)
 {
-       struct nouveau_drm *drm = data;
-       drm_handle_vblank(drm->dev, head);
-       return NVKM_EVENT_KEEP;
+       struct nouveau_crtc *nv_crtc =
+               container_of(notify, typeof(*nv_crtc), vblank);
+       drm_handle_vblank(nv_crtc->base.dev, nv_crtc->index);
+       return NVKM_NOTIFY_KEEP;
 }
 
 int
 nouveau_display_vblank_enable(struct drm_device *dev, int head)
 {
-       struct nouveau_display *disp = nouveau_display(dev);
-       if (disp) {
-               nouveau_event_get(disp->vblank[head]);
-               return 0;
+       struct drm_crtc *crtc;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               if (nv_crtc->index == head) {
+                       nvkm_notify_get(&nv_crtc->vblank);
+                       return 0;
+               }
        }
-       return -EIO;
+       return -EINVAL;
 }
 
 void
 nouveau_display_vblank_disable(struct drm_device *dev, int head)
 {
-       struct nouveau_display *disp = nouveau_display(dev);
-       if (disp)
-               nouveau_event_put(disp->vblank[head]);
+       struct drm_crtc *crtc;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               if (nv_crtc->index == head) {
+                       nvkm_notify_put(&nv_crtc->vblank);
+                       return;
+               }
+       }
 }
 
 static inline int
@@ -151,36 +161,34 @@ nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error,
 static void
 nouveau_display_vblank_fini(struct drm_device *dev)
 {
-       struct nouveau_display *disp = nouveau_display(dev);
-       int i;
+       struct drm_crtc *crtc;
 
        drm_vblank_cleanup(dev);
 
-       if (disp->vblank) {
-               for (i = 0; i < dev->mode_config.num_crtc; i++)
-                       nouveau_event_ref(NULL, &disp->vblank[i]);
-               kfree(disp->vblank);
-               disp->vblank = NULL;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               nvkm_notify_fini(&nv_crtc->vblank);
        }
 }
 
 static int
 nouveau_display_vblank_init(struct drm_device *dev)
 {
-       struct nouveau_display *disp = nouveau_display(dev);
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_disp *pdisp = nouveau_disp(drm->device);
-       int ret, i;
-
-       disp->vblank = kzalloc(dev->mode_config.num_crtc *
-                              sizeof(*disp->vblank), GFP_KERNEL);
-       if (!disp->vblank)
-               return -ENOMEM;
+       struct drm_crtc *crtc;
+       int ret;
 
-       for (i = 0; i < dev->mode_config.num_crtc; i++) {
-               ret = nouveau_event_new(pdisp->vblank, 1, i,
-                                       nouveau_display_vblank_handler,
-                                       drm, &disp->vblank[i]);
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+               ret = nvkm_notify_init(&pdisp->vblank,
+                                      nouveau_display_vblank_handler, false,
+                                      &(struct nvif_notify_head_req_v0) {
+                                       .head = nv_crtc->index,
+                                      },
+                                      sizeof(struct nvif_notify_head_req_v0),
+                                      sizeof(struct nvif_notify_head_rep_v0),
+                                      &nv_crtc->vblank);
                if (ret) {
                        nouveau_display_vblank_fini(dev);
                        return ret;
@@ -200,6 +208,10 @@ static void
 nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
 {
        struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
+       struct nouveau_display *disp = nouveau_display(drm_fb->dev);
+
+       if (disp->fb_dtor)
+               disp->fb_dtor(drm_fb);
 
        if (fb->nvbo)
                drm_gem_object_unreference_unlocked(&fb->nvbo->gem);
@@ -229,63 +241,24 @@ nouveau_framebuffer_init(struct drm_device *dev,
                         struct drm_mode_fb_cmd2 *mode_cmd,
                         struct nouveau_bo *nvbo)
 {
-       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_display *disp = nouveau_display(dev);
        struct drm_framebuffer *fb = &nv_fb->base;
        int ret;
 
        drm_helper_mode_fill_fb_struct(fb, mode_cmd);
        nv_fb->nvbo = nvbo;
 
-       if (nv_device(drm->device)->card_type >= NV_50) {
-               u32 tile_flags = nouveau_bo_tile_layout(nvbo);
-               if (tile_flags == 0x7a00 ||
-                   tile_flags == 0xfe00)
-                       nv_fb->r_dma = NvEvoFB32;
-               else
-               if (tile_flags == 0x7000)
-                       nv_fb->r_dma = NvEvoFB16;
-               else
-                       nv_fb->r_dma = NvEvoVRAM_LP;
-
-               switch (fb->depth) {
-               case  8: nv_fb->r_format = 0x1e00; break;
-               case 15: nv_fb->r_format = 0xe900; break;
-               case 16: nv_fb->r_format = 0xe800; break;
-               case 24:
-               case 32: nv_fb->r_format = 0xcf00; break;
-               case 30: nv_fb->r_format = 0xd100; break;
-               default:
-                        NV_ERROR(drm, "unknown depth %d\n", fb->depth);
-                        return -EINVAL;
-               }
-
-               if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
-                       NV_ERROR(drm, "framebuffer requires contiguous bo\n");
-                       return -EINVAL;
-               }
-
-               if (nv_device(drm->device)->chipset == 0x50)
-                       nv_fb->r_format |= (tile_flags << 8);
-
-               if (!tile_flags) {
-                       if (nv_device(drm->device)->card_type < NV_D0)
-                               nv_fb->r_pitch = 0x00100000 | fb->pitches[0];
-                       else
-                               nv_fb->r_pitch = 0x01000000 | fb->pitches[0];
-               } else {
-                       u32 mode = nvbo->tile_mode;
-                       if (nv_device(drm->device)->card_type >= NV_C0)
-                               mode >>= 4;
-                       nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode;
-               }
-       }
-
        ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
-       if (ret) {
+       if (ret)
                return ret;
+
+       if (disp->fb_ctor) {
+               ret = disp->fb_ctor(fb);
+               if (ret)
+                       disp->fb_dtor(fb);
        }
 
-       return 0;
+       return ret;
 }
 
 static struct drm_framebuffer *
@@ -393,7 +366,7 @@ nouveau_display_init(struct drm_device *dev)
        /* enable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               if (conn->hpd) nouveau_event_get(conn->hpd);
+               nvkm_notify_get(&conn->hpd);
        }
 
        return ret;
@@ -404,11 +377,16 @@ nouveau_display_fini(struct drm_device *dev)
 {
        struct nouveau_display *disp = nouveau_display(dev);
        struct drm_connector *connector;
+       int head;
+
+       /* Make sure that drm and hw vblank irqs get properly disabled. */
+       for (head = 0; head < dev->mode_config.num_crtc; head++)
+               drm_vblank_off(dev, head);
 
        /* disable hotplug interrupts */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct nouveau_connector *conn = nouveau_connector(connector);
-               if (conn->hpd) nouveau_event_put(conn->hpd);
+               nvkm_notify_put(&conn->hpd);
        }
 
        drm_kms_helper_poll_disable(dev);
@@ -620,6 +598,8 @@ void
 nouveau_display_resume(struct drm_device *dev)
 {
        struct drm_crtc *crtc;
+       int head;
+
        nouveau_display_init(dev);
 
        /* Force CLUT to get re-loaded during modeset */
@@ -629,6 +609,10 @@ nouveau_display_resume(struct drm_device *dev)
                nv_crtc->lut.depth = 0;
        }
 
+       /* Make sure that drm and hw vblank irqs get resumed if needed. */
+       for (head = 0; head < dev->mode_config.num_crtc; head++)
+               drm_vblank_on(dev, head);
+
        drm_helper_resume_force_mode(dev);
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {