linux/drivers/gpu/drm/nouveau/nouveau_display.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008 Maarten Maathuis.
   3 * All Rights Reserved.
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining
   6 * a copy of this software and associated documentation files (the
   7 * "Software"), to deal in the Software without restriction, including
   8 * without limitation the rights to use, copy, modify, merge, publish,
   9 * distribute, sublicense, and/or sell copies of the Software, and to
  10 * permit persons to whom the Software is furnished to do so, subject to
  11 * the following conditions:
  12 *
  13 * The above copyright notice and this permission notice (including the
  14 * next paragraph) shall be included in all copies or substantial
  15 * portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24 *
  25 */
  26
  27#include <drm/drmP.h>
  28#include <drm/drm_crtc_helper.h>
  29#include <drm/ttm/ttm_execbuf_util.h>
  30
  31#include "nouveau_fbcon.h"
  32#include "dispnv04/hw.h"
  33#include "nouveau_crtc.h"
  34#include "nouveau_dma.h"
  35#include "nouveau_gem.h"
  36#include "nouveau_connector.h"
  37#include "nv50_display.h"
  38
  39#include "nouveau_fence.h"
  40
  41#include <subdev/bios/gpio.h>
  42#include <subdev/gpio.h>
  43#include <engine/disp.h>
  44
  45#include <core/class.h>
  46
  47static void
  48nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
  49{
  50        struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
  51
  52        if (fb->nvbo)
  53                drm_gem_object_unreference_unlocked(fb->nvbo->gem);
  54
  55        drm_framebuffer_cleanup(drm_fb);
  56        kfree(fb);
  57}
  58
  59static int
  60nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb,
  61                                       struct drm_file *file_priv,
  62                                       unsigned int *handle)
  63{
  64        struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
  65
  66        return drm_gem_handle_create(file_priv, fb->nvbo->gem, handle);
  67}
  68
  69static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
  70        .destroy = nouveau_user_framebuffer_destroy,
  71        .create_handle = nouveau_user_framebuffer_create_handle,
  72};
  73
  74int
  75nouveau_framebuffer_init(struct drm_device *dev,
  76                         struct nouveau_framebuffer *nv_fb,
  77                         struct drm_mode_fb_cmd2 *mode_cmd,
  78                         struct nouveau_bo *nvbo)
  79{
  80        struct nouveau_drm *drm = nouveau_drm(dev);
  81        struct drm_framebuffer *fb = &nv_fb->base;
  82        int ret;
  83
  84        drm_helper_mode_fill_fb_struct(fb, mode_cmd);
  85        nv_fb->nvbo = nvbo;
  86
  87        if (nv_device(drm->device)->card_type >= NV_50) {
  88                u32 tile_flags = nouveau_bo_tile_layout(nvbo);
  89                if (tile_flags == 0x7a00 ||
  90                    tile_flags == 0xfe00)
  91                        nv_fb->r_dma = NvEvoFB32;
  92                else
  93                if (tile_flags == 0x7000)
  94                        nv_fb->r_dma = NvEvoFB16;
  95                else
  96                        nv_fb->r_dma = NvEvoVRAM_LP;
  97
  98                switch (fb->depth) {
  99                case  8: nv_fb->r_format = 0x1e00; break;
 100                case 15: nv_fb->r_format = 0xe900; break;
 101                case 16: nv_fb->r_format = 0xe800; break;
 102                case 24:
 103                case 32: nv_fb->r_format = 0xcf00; break;
 104                case 30: nv_fb->r_format = 0xd100; break;
 105                default:
 106                         NV_ERROR(drm, "unknown depth %d\n", fb->depth);
 107                         return -EINVAL;
 108                }
 109
 110                if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
 111                        NV_ERROR(drm, "framebuffer requires contiguous bo\n");
 112                        return -EINVAL;
 113                }
 114
 115                if (nv_device(drm->device)->chipset == 0x50)
 116                        nv_fb->r_format |= (tile_flags << 8);
 117
 118                if (!tile_flags) {
 119                        if (nv_device(drm->device)->card_type < NV_D0)
 120                                nv_fb->r_pitch = 0x00100000 | fb->pitches[0];
 121                        else
 122                                nv_fb->r_pitch = 0x01000000 | fb->pitches[0];
 123                } else {
 124                        u32 mode = nvbo->tile_mode;
 125                        if (nv_device(drm->device)->card_type >= NV_C0)
 126                                mode >>= 4;
 127                        nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode;
 128                }
 129        }
 130
 131        ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
 132        if (ret) {
 133                return ret;
 134        }
 135
 136        return 0;
 137}
 138
 139static struct drm_framebuffer *
 140nouveau_user_framebuffer_create(struct drm_device *dev,
 141                                struct drm_file *file_priv,
 142                                struct drm_mode_fb_cmd2 *mode_cmd)
 143{
 144        struct nouveau_framebuffer *nouveau_fb;
 145        struct drm_gem_object *gem;
 146        int ret = -ENOMEM;
 147
 148        gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
 149        if (!gem)
 150                return ERR_PTR(-ENOENT);
 151
 152        nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
 153        if (!nouveau_fb)
 154                goto err_unref;
 155
 156        ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
 157        if (ret)
 158                goto err;
 159
 160        return &nouveau_fb->base;
 161
 162err:
 163        kfree(nouveau_fb);
 164err_unref:
 165        drm_gem_object_unreference(gem);
 166        return ERR_PTR(ret);
 167}
 168
 169static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
 170        .fb_create = nouveau_user_framebuffer_create,
 171        .output_poll_changed = nouveau_fbcon_output_poll_changed,
 172};
 173
 174
 175struct nouveau_drm_prop_enum_list {
 176        u8 gen_mask;
 177        int type;
 178        char *name;
 179};
 180
 181static struct nouveau_drm_prop_enum_list underscan[] = {
 182        { 6, UNDERSCAN_AUTO, "auto" },
 183        { 6, UNDERSCAN_OFF, "off" },
 184        { 6, UNDERSCAN_ON, "on" },
 185        {}
 186};
 187
 188static struct nouveau_drm_prop_enum_list dither_mode[] = {
 189        { 7, DITHERING_MODE_AUTO, "auto" },
 190        { 7, DITHERING_MODE_OFF, "off" },
 191        { 1, DITHERING_MODE_ON, "on" },
 192        { 6, DITHERING_MODE_STATIC2X2, "static 2x2" },
 193        { 6, DITHERING_MODE_DYNAMIC2X2, "dynamic 2x2" },
 194        { 4, DITHERING_MODE_TEMPORAL, "temporal" },
 195        {}
 196};
 197
 198static struct nouveau_drm_prop_enum_list dither_depth[] = {
 199        { 6, DITHERING_DEPTH_AUTO, "auto" },
 200        { 6, DITHERING_DEPTH_6BPC, "6 bpc" },
 201        { 6, DITHERING_DEPTH_8BPC, "8 bpc" },
 202        {}
 203};
 204
 205#define PROP_ENUM(p,gen,n,list) do {                                           \
 206        struct nouveau_drm_prop_enum_list *l = (list);                         \
 207        int c = 0;                                                             \
 208        while (l->gen_mask) {                                                  \
 209                if (l->gen_mask & (1 << (gen)))                                \
 210                        c++;                                                   \
 211                l++;                                                           \
 212        }                                                                      \
 213        if (c) {                                                               \
 214                p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c);        \
 215                l = (list);                                                    \
 216                c = 0;                                                         \
 217                while (p && l->gen_mask) {                                     \
 218                        if (l->gen_mask & (1 << (gen))) {                      \
 219                                drm_property_add_enum(p, c, l->type, l->name); \
 220                                c++;                                           \
 221                        }                                                      \
 222                        l++;                                                   \
 223                }                                                              \
 224        }                                                                      \
 225} while(0)
 226
 227int
 228nouveau_display_init(struct drm_device *dev)
 229{
 230        struct nouveau_drm *drm = nouveau_drm(dev);
 231        struct nouveau_display *disp = nouveau_display(dev);
 232        struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
 233        struct drm_connector *connector;
 234        int ret;
 235
 236        ret = disp->init(dev);
 237        if (ret)
 238                return ret;
 239
 240        /* enable polling for external displays */
 241        drm_kms_helper_poll_enable(dev);
 242
 243        /* enable hotplug interrupts */
 244        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 245                struct nouveau_connector *conn = nouveau_connector(connector);
 246                if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
 247                        nouveau_event_get(gpio->events, conn->hpd.line,
 248                                         &conn->hpd_func);
 249                }
 250        }
 251
 252        return ret;
 253}
 254
 255void
 256nouveau_display_fini(struct drm_device *dev)
 257{
 258        struct nouveau_drm *drm = nouveau_drm(dev);
 259        struct nouveau_display *disp = nouveau_display(dev);
 260        struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
 261        struct drm_connector *connector;
 262
 263        /* disable hotplug interrupts */
 264        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 265                struct nouveau_connector *conn = nouveau_connector(connector);
 266                if (gpio && conn->hpd.func != DCB_GPIO_UNUSED) {
 267                        nouveau_event_put(gpio->events, conn->hpd.line,
 268                                         &conn->hpd_func);
 269                }
 270        }
 271
 272        drm_kms_helper_poll_disable(dev);
 273        disp->fini(dev);
 274}
 275
 276int
 277nouveau_display_create(struct drm_device *dev)
 278{
 279        struct nouveau_drm *drm = nouveau_drm(dev);
 280        struct nouveau_display *disp;
 281        int ret, gen;
 282
 283        disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
 284        if (!disp)
 285                return -ENOMEM;
 286
 287        drm_mode_config_init(dev);
 288        drm_mode_create_scaling_mode_property(dev);
 289        drm_mode_create_dvi_i_properties(dev);
 290
 291        if (nv_device(drm->device)->card_type < NV_50)
 292                gen = 0;
 293        else
 294        if (nv_device(drm->device)->card_type < NV_D0)
 295                gen = 1;
 296        else
 297                gen = 2;
 298
 299        PROP_ENUM(disp->dithering_mode, gen, "dithering mode", dither_mode);
 300        PROP_ENUM(disp->dithering_depth, gen, "dithering depth", dither_depth);
 301        PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
 302
 303        disp->underscan_hborder_property =
 304                drm_property_create_range(dev, 0, "underscan hborder", 0, 128);
 305
 306        disp->underscan_vborder_property =
 307                drm_property_create_range(dev, 0, "underscan vborder", 0, 128);
 308
 309        if (gen >= 1) {
 310                /* -90..+90 */
 311                disp->vibrant_hue_property =
 312                        drm_property_create_range(dev, 0, "vibrant hue", 0, 180);
 313
 314                /* -100..+100 */
 315                disp->color_vibrance_property =
 316                        drm_property_create_range(dev, 0, "color vibrance", 0, 200);
 317        }
 318
 319        dev->mode_config.funcs = &nouveau_mode_config_funcs;
 320        dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
 321
 322        dev->mode_config.min_width = 0;
 323        dev->mode_config.min_height = 0;
 324        if (nv_device(drm->device)->card_type < NV_10) {
 325                dev->mode_config.max_width = 2048;
 326                dev->mode_config.max_height = 2048;
 327        } else
 328        if (nv_device(drm->device)->card_type < NV_50) {
 329                dev->mode_config.max_width = 4096;
 330                dev->mode_config.max_height = 4096;
 331        } else {
 332                dev->mode_config.max_width = 8192;
 333                dev->mode_config.max_height = 8192;
 334        }
 335
 336        dev->mode_config.preferred_depth = 24;
 337        dev->mode_config.prefer_shadow = 1;
 338
 339        drm_kms_helper_poll_init(dev);
 340        drm_kms_helper_poll_disable(dev);
 341
 342        if (drm->vbios.dcb.entries) {
 343                if (nv_device(drm->device)->card_type < NV_50)
 344                        ret = nv04_display_create(dev);
 345                else
 346                        ret = nv50_display_create(dev);
 347        } else {
 348                ret = 0;
 349        }
 350
 351        if (ret)
 352                goto disp_create_err;
 353
 354        if (dev->mode_config.num_crtc) {
 355                ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
 356                if (ret)
 357                        goto vblank_err;
 358        }
 359
 360        nouveau_backlight_init(dev);
 361        return 0;
 362
 363vblank_err:
 364        disp->dtor(dev);
 365disp_create_err:
 366        drm_kms_helper_poll_fini(dev);
 367        drm_mode_config_cleanup(dev);
 368        return ret;
 369}
 370
 371void
 372nouveau_display_destroy(struct drm_device *dev)
 373{
 374        struct nouveau_display *disp = nouveau_display(dev);
 375
 376        nouveau_backlight_exit(dev);
 377        drm_vblank_cleanup(dev);
 378
 379        drm_kms_helper_poll_fini(dev);
 380        drm_mode_config_cleanup(dev);
 381
 382        if (disp->dtor)
 383                disp->dtor(dev);
 384
 385        nouveau_drm(dev)->display = NULL;
 386        kfree(disp);
 387}
 388
 389int
 390nouveau_display_suspend(struct drm_device *dev)
 391{
 392        struct nouveau_drm *drm = nouveau_drm(dev);
 393        struct drm_crtc *crtc;
 394
 395        nouveau_display_fini(dev);
 396
 397        NV_SUSPEND(drm, "unpinning framebuffer(s)...\n");
 398        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 399                struct nouveau_framebuffer *nouveau_fb;
 400
 401                nouveau_fb = nouveau_framebuffer(crtc->fb);
 402                if (!nouveau_fb || !nouveau_fb->nvbo)
 403                        continue;
 404
 405                nouveau_bo_unpin(nouveau_fb->nvbo);
 406        }
 407
 408        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 409                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 410
 411                nouveau_bo_unmap(nv_crtc->cursor.nvbo);
 412                nouveau_bo_unpin(nv_crtc->cursor.nvbo);
 413        }
 414
 415        return 0;
 416}
 417
 418void
 419nouveau_display_repin(struct drm_device *dev)
 420{
 421        struct nouveau_drm *drm = nouveau_drm(dev);
 422        struct drm_crtc *crtc;
 423        int ret;
 424
 425        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 426                struct nouveau_framebuffer *nouveau_fb;
 427
 428                nouveau_fb = nouveau_framebuffer(crtc->fb);
 429                if (!nouveau_fb || !nouveau_fb->nvbo)
 430                        continue;
 431
 432                nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
 433        }
 434
 435        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 436                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 437
 438                ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
 439                if (!ret)
 440                        ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
 441                if (ret)
 442                        NV_ERROR(drm, "Could not pin/map cursor.\n");
 443        }
 444}
 445
 446void
 447nouveau_display_resume(struct drm_device *dev)
 448{
 449        struct drm_crtc *crtc;
 450        nouveau_display_init(dev);
 451
 452        /* Force CLUT to get re-loaded during modeset */
 453        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 454                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 455
 456                nv_crtc->lut.depth = 0;
 457        }
 458
 459        drm_helper_resume_force_mode(dev);
 460
 461        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 462                struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 463                u32 offset = nv_crtc->cursor.nvbo->bo.offset;
 464
 465                nv_crtc->cursor.set_offset(nv_crtc, offset);
 466                nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
 467                                                 nv_crtc->cursor_saved_y);
 468        }
 469}
 470
 471static int
 472nouveau_page_flip_emit(struct nouveau_channel *chan,
 473                       struct nouveau_bo *old_bo,
 474                       struct nouveau_bo *new_bo,
 475                       struct nouveau_page_flip_state *s,
 476                       struct nouveau_fence **pfence)
 477{
 478        struct nouveau_fence_chan *fctx = chan->fence;
 479        struct nouveau_drm *drm = chan->drm;
 480        struct drm_device *dev = drm->dev;
 481        unsigned long flags;
 482        int ret;
 483
 484        /* Queue it to the pending list */
 485        spin_lock_irqsave(&dev->event_lock, flags);
 486        list_add_tail(&s->head, &fctx->flip);
 487        spin_unlock_irqrestore(&dev->event_lock, flags);
 488
 489        /* Synchronize with the old framebuffer */
 490        ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan);
 491        if (ret)
 492                goto fail;
 493
 494        /* Emit the pageflip */
 495        ret = RING_SPACE(chan, 3);
 496        if (ret)
 497                goto fail;
 498
 499        if (nv_device(drm->device)->card_type < NV_C0) {
 500                BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
 501                OUT_RING  (chan, 0x00000000);
 502                OUT_RING  (chan, 0x00000000);
 503        } else {
 504                BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
 505                OUT_RING  (chan, 0);
 506                BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000);
 507        }
 508        FIRE_RING (chan);
 509
 510        ret = nouveau_fence_new(chan, false, pfence);
 511        if (ret)
 512                goto fail;
 513
 514        return 0;
 515fail:
 516        spin_lock_irqsave(&dev->event_lock, flags);
 517        list_del(&s->head);
 518        spin_unlock_irqrestore(&dev->event_lock, flags);
 519        return ret;
 520}
 521
 522int
 523nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 524                       struct drm_pending_vblank_event *event,
 525                       uint32_t page_flip_flags)
 526{
 527        struct drm_device *dev = crtc->dev;
 528        struct nouveau_drm *drm = nouveau_drm(dev);
 529        struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
 530        struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
 531        struct nouveau_page_flip_state *s;
 532        struct nouveau_channel *chan = NULL;
 533        struct nouveau_fence *fence;
 534        struct ttm_validate_buffer resv[2] = {
 535                { .bo = &old_bo->bo },
 536                { .bo = &new_bo->bo },
 537        };
 538        struct ww_acquire_ctx ticket;
 539        LIST_HEAD(res);
 540        int ret;
 541
 542        if (!drm->channel)
 543                return -ENODEV;
 544
 545        s = kzalloc(sizeof(*s), GFP_KERNEL);
 546        if (!s)
 547                return -ENOMEM;
 548
 549        /* Choose the channel the flip will be handled in */
 550        spin_lock(&old_bo->bo.bdev->fence_lock);
 551        fence = new_bo->bo.sync_obj;
 552        if (fence)
 553                chan = fence->channel;
 554        if (!chan)
 555                chan = drm->channel;
 556        spin_unlock(&old_bo->bo.bdev->fence_lock);
 557
 558        if (new_bo != old_bo) {
 559                ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
 560                if (ret)
 561                        goto fail_free;
 562
 563                list_add(&resv[1].head, &res);
 564        }
 565        list_add(&resv[0].head, &res);
 566
 567        mutex_lock(&chan->cli->mutex);
 568        ret = ttm_eu_reserve_buffers(&ticket, &res);
 569        if (ret)
 570                goto fail_unpin;
 571
 572        /* Initialize a page flip struct */
 573        *s = (struct nouveau_page_flip_state)
 574                { { }, event, nouveau_crtc(crtc)->index,
 575                  fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
 576                  new_bo->bo.offset };
 577
 578        /* Emit a page flip */
 579        if (nv_device(drm->device)->card_type >= NV_50) {
 580                ret = nv50_display_flip_next(crtc, fb, chan, 0);
 581                if (ret)
 582                        goto fail_unreserve;
 583        } else {
 584                struct nv04_display *dispnv04 = nv04_display(dev);
 585                nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]);
 586        }
 587
 588        ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
 589        mutex_unlock(&chan->cli->mutex);
 590        if (ret)
 591                goto fail_unreserve;
 592
 593        /* Update the crtc struct and cleanup */
 594        crtc->fb = fb;
 595
 596        ttm_eu_fence_buffer_objects(&ticket, &res, fence);
 597        if (old_bo != new_bo)
 598                nouveau_bo_unpin(old_bo);
 599        nouveau_fence_unref(&fence);
 600        return 0;
 601
 602fail_unreserve:
 603        ttm_eu_backoff_reservation(&ticket, &res);
 604fail_unpin:
 605        mutex_unlock(&chan->cli->mutex);
 606        if (old_bo != new_bo)
 607                nouveau_bo_unpin(new_bo);
 608fail_free:
 609        kfree(s);
 610        return ret;
 611}
 612
 613int
 614nouveau_finish_page_flip(struct nouveau_channel *chan,
 615                         struct nouveau_page_flip_state *ps)
 616{
 617        struct nouveau_fence_chan *fctx = chan->fence;
 618        struct nouveau_drm *drm = chan->drm;
 619        struct drm_device *dev = drm->dev;
 620        struct nouveau_page_flip_state *s;
 621        unsigned long flags;
 622
 623        spin_lock_irqsave(&dev->event_lock, flags);
 624
 625        if (list_empty(&fctx->flip)) {
 626                NV_ERROR(drm, "unexpected pageflip\n");
 627                spin_unlock_irqrestore(&dev->event_lock, flags);
 628                return -EINVAL;
 629        }
 630
 631        s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
 632        if (s->event)
 633                drm_send_vblank_event(dev, -1, s->event);
 634
 635        list_del(&s->head);
 636        if (ps)
 637                *ps = *s;
 638        kfree(s);
 639
 640        spin_unlock_irqrestore(&dev->event_lock, flags);
 641        return 0;
 642}
 643
 644int
 645nouveau_flip_complete(void *data)
 646{
 647        struct nouveau_channel *chan = data;
 648        struct nouveau_drm *drm = chan->drm;
 649        struct nouveau_page_flip_state state;
 650
 651        if (!nouveau_finish_page_flip(chan, &state)) {
 652                if (nv_device(drm->device)->card_type < NV_50) {
 653                        nv_set_crtc_base(drm->dev, state.crtc, state.offset +
 654                                         state.y * state.pitch +
 655                                         state.x * state.bpp / 8);
 656                }
 657        }
 658
 659        return 0;
 660}
 661
 662int
 663nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
 664                            struct drm_mode_create_dumb *args)
 665{
 666        struct nouveau_bo *bo;
 667        int ret;
 668
 669        args->pitch = roundup(args->width * (args->bpp / 8), 256);
 670        args->size = args->pitch * args->height;
 671        args->size = roundup(args->size, PAGE_SIZE);
 672
 673        ret = nouveau_gem_new(dev, args->size, 0, NOUVEAU_GEM_DOMAIN_VRAM, 0, 0, &bo);
 674        if (ret)
 675                return ret;
 676
 677        ret = drm_gem_handle_create(file_priv, bo->gem, &args->handle);
 678        drm_gem_object_unreference_unlocked(bo->gem);
 679        return ret;
 680}
 681
 682int
 683nouveau_display_dumb_map_offset(struct drm_file *file_priv,
 684                                struct drm_device *dev,
 685                                uint32_t handle, uint64_t *poffset)
 686{
 687        struct drm_gem_object *gem;
 688
 689        gem = drm_gem_object_lookup(dev, file_priv, handle);
 690        if (gem) {
 691                struct nouveau_bo *bo = gem->driver_private;
 692                *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node);
 693                drm_gem_object_unreference_unlocked(gem);
 694                return 0;
 695        }
 696
 697        return -ENOENT;
 698}
 699