root/drivers/gpu/drm/nouveau/nouveau_display.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nouveau_display_vblank_handler
  2. nouveau_display_vblank_enable
  3. nouveau_display_vblank_disable
  4. calc
  5. nouveau_display_scanoutpos_head
  6. nouveau_display_scanoutpos
  7. nouveau_display_vblank_fini
  8. nouveau_display_vblank_init
  9. nouveau_user_framebuffer_destroy
  10. nouveau_user_framebuffer_create_handle
  11. nouveau_framebuffer_new
  12. nouveau_user_framebuffer_create
  13. nouveau_display_hpd_work
  14. nouveau_display_acpi_ntfy
  15. nouveau_display_init
  16. nouveau_display_fini
  17. nouveau_display_create_properties
  18. nouveau_display_create
  19. nouveau_display_destroy
  20. nouveau_display_suspend
  21. nouveau_display_resume
  22. nouveau_display_dumb_create
  23. nouveau_display_dumb_map_offset

   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 <acpi/video.h>
  28 
  29 #include <drm/drm_atomic.h>
  30 #include <drm/drm_atomic_helper.h>
  31 #include <drm/drm_crtc_helper.h>
  32 #include <drm/drm_fb_helper.h>
  33 #include <drm/drm_fourcc.h>
  34 #include <drm/drm_probe_helper.h>
  35 #include <drm/drm_vblank.h>
  36 
  37 #include "nouveau_fbcon.h"
  38 #include "nouveau_crtc.h"
  39 #include "nouveau_gem.h"
  40 #include "nouveau_connector.h"
  41 #include "nv50_display.h"
  42 
  43 #include <nvif/class.h>
  44 #include <nvif/cl0046.h>
  45 #include <nvif/event.h>
  46 
  47 static int
  48 nouveau_display_vblank_handler(struct nvif_notify *notify)
  49 {
  50         struct nouveau_crtc *nv_crtc =
  51                 container_of(notify, typeof(*nv_crtc), vblank);
  52         drm_crtc_handle_vblank(&nv_crtc->base);
  53         return NVIF_NOTIFY_KEEP;
  54 }
  55 
  56 int
  57 nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
  58 {
  59         struct drm_crtc *crtc;
  60         struct nouveau_crtc *nv_crtc;
  61 
  62         crtc = drm_crtc_from_index(dev, pipe);
  63         if (!crtc)
  64                 return -EINVAL;
  65 
  66         nv_crtc = nouveau_crtc(crtc);
  67         nvif_notify_get(&nv_crtc->vblank);
  68 
  69         return 0;
  70 }
  71 
  72 void
  73 nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
  74 {
  75         struct drm_crtc *crtc;
  76         struct nouveau_crtc *nv_crtc;
  77 
  78         crtc = drm_crtc_from_index(dev, pipe);
  79         if (!crtc)
  80                 return;
  81 
  82         nv_crtc = nouveau_crtc(crtc);
  83         nvif_notify_put(&nv_crtc->vblank);
  84 }
  85 
  86 static inline int
  87 calc(int blanks, int blanke, int total, int line)
  88 {
  89         if (blanke >= blanks) {
  90                 if (line >= blanks)
  91                         line -= total;
  92         } else {
  93                 if (line >= blanks)
  94                         line -= total;
  95                 line -= blanke + 1;
  96         }
  97         return line;
  98 }
  99 
 100 static bool
 101 nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
 102                                 ktime_t *stime, ktime_t *etime)
 103 {
 104         struct {
 105                 struct nv04_disp_mthd_v0 base;
 106                 struct nv04_disp_scanoutpos_v0 scan;
 107         } args = {
 108                 .base.method = NV04_DISP_SCANOUTPOS,
 109                 .base.head = nouveau_crtc(crtc)->index,
 110         };
 111         struct nouveau_display *disp = nouveau_display(crtc->dev);
 112         struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
 113         int retry = 20;
 114         bool ret = false;
 115 
 116         do {
 117                 ret = nvif_mthd(&disp->disp.object, 0, &args, sizeof(args));
 118                 if (ret != 0)
 119                         return false;
 120 
 121                 if (args.scan.vline) {
 122                         ret = true;
 123                         break;
 124                 }
 125 
 126                 if (retry) ndelay(vblank->linedur_ns);
 127         } while (retry--);
 128 
 129         *hpos = args.scan.hline;
 130         *vpos = calc(args.scan.vblanks, args.scan.vblanke,
 131                      args.scan.vtotal, args.scan.vline);
 132         if (stime) *stime = ns_to_ktime(args.scan.time[0]);
 133         if (etime) *etime = ns_to_ktime(args.scan.time[1]);
 134 
 135         return ret;
 136 }
 137 
 138 bool
 139 nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe,
 140                            bool in_vblank_irq, int *vpos, int *hpos,
 141                            ktime_t *stime, ktime_t *etime,
 142                            const struct drm_display_mode *mode)
 143 {
 144         struct drm_crtc *crtc;
 145 
 146         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 147                 if (nouveau_crtc(crtc)->index == pipe) {
 148                         return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
 149                                                                stime, etime);
 150                 }
 151         }
 152 
 153         return false;
 154 }
 155 
 156 static void
 157 nouveau_display_vblank_fini(struct drm_device *dev)
 158 {
 159         struct drm_crtc *crtc;
 160 
 161         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 162                 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 163                 nvif_notify_fini(&nv_crtc->vblank);
 164         }
 165 }
 166 
 167 static int
 168 nouveau_display_vblank_init(struct drm_device *dev)
 169 {
 170         struct nouveau_display *disp = nouveau_display(dev);
 171         struct drm_crtc *crtc;
 172         int ret;
 173 
 174         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 175                 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 176                 ret = nvif_notify_init(&disp->disp.object,
 177                                        nouveau_display_vblank_handler, false,
 178                                        NV04_DISP_NTFY_VBLANK,
 179                                        &(struct nvif_notify_head_req_v0) {
 180                                         .head = nv_crtc->index,
 181                                        },
 182                                        sizeof(struct nvif_notify_head_req_v0),
 183                                        sizeof(struct nvif_notify_head_rep_v0),
 184                                        &nv_crtc->vblank);
 185                 if (ret) {
 186                         nouveau_display_vblank_fini(dev);
 187                         return ret;
 188                 }
 189         }
 190 
 191         ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
 192         if (ret) {
 193                 nouveau_display_vblank_fini(dev);
 194                 return ret;
 195         }
 196 
 197         return 0;
 198 }
 199 
 200 static void
 201 nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
 202 {
 203         struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
 204 
 205         if (fb->nvbo)
 206                 drm_gem_object_put_unlocked(&fb->nvbo->bo.base);
 207 
 208         drm_framebuffer_cleanup(drm_fb);
 209         kfree(fb);
 210 }
 211 
 212 static int
 213 nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb,
 214                                        struct drm_file *file_priv,
 215                                        unsigned int *handle)
 216 {
 217         struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
 218 
 219         return drm_gem_handle_create(file_priv, &fb->nvbo->bo.base, handle);
 220 }
 221 
 222 static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
 223         .destroy = nouveau_user_framebuffer_destroy,
 224         .create_handle = nouveau_user_framebuffer_create_handle,
 225 };
 226 
 227 int
 228 nouveau_framebuffer_new(struct drm_device *dev,
 229                         const struct drm_mode_fb_cmd2 *mode_cmd,
 230                         struct nouveau_bo *nvbo,
 231                         struct nouveau_framebuffer **pfb)
 232 {
 233         struct nouveau_drm *drm = nouveau_drm(dev);
 234         struct nouveau_framebuffer *fb;
 235         int ret;
 236 
 237         /* YUV overlays have special requirements pre-NV50 */
 238         if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA &&
 239 
 240             (mode_cmd->pixel_format == DRM_FORMAT_YUYV ||
 241              mode_cmd->pixel_format == DRM_FORMAT_UYVY ||
 242              mode_cmd->pixel_format == DRM_FORMAT_NV12 ||
 243              mode_cmd->pixel_format == DRM_FORMAT_NV21) &&
 244             (mode_cmd->pitches[0] & 0x3f || /* align 64 */
 245              mode_cmd->pitches[0] >= 0x10000 || /* at most 64k pitch */
 246              (mode_cmd->pitches[1] && /* pitches for planes must match */
 247               mode_cmd->pitches[0] != mode_cmd->pitches[1]))) {
 248                 struct drm_format_name_buf format_name;
 249                 DRM_DEBUG_KMS("Unsuitable framebuffer: format: %s; pitches: 0x%x\n 0x%x\n",
 250                               drm_get_format_name(mode_cmd->pixel_format,
 251                                                   &format_name),
 252                               mode_cmd->pitches[0],
 253                               mode_cmd->pitches[1]);
 254                 return -EINVAL;
 255         }
 256 
 257         if (!(fb = *pfb = kzalloc(sizeof(*fb), GFP_KERNEL)))
 258                 return -ENOMEM;
 259 
 260         drm_helper_mode_fill_fb_struct(dev, &fb->base, mode_cmd);
 261         fb->nvbo = nvbo;
 262 
 263         ret = drm_framebuffer_init(dev, &fb->base, &nouveau_framebuffer_funcs);
 264         if (ret)
 265                 kfree(fb);
 266         return ret;
 267 }
 268 
 269 struct drm_framebuffer *
 270 nouveau_user_framebuffer_create(struct drm_device *dev,
 271                                 struct drm_file *file_priv,
 272                                 const struct drm_mode_fb_cmd2 *mode_cmd)
 273 {
 274         struct nouveau_framebuffer *fb;
 275         struct nouveau_bo *nvbo;
 276         struct drm_gem_object *gem;
 277         int ret;
 278 
 279         gem = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]);
 280         if (!gem)
 281                 return ERR_PTR(-ENOENT);
 282         nvbo = nouveau_gem_object(gem);
 283 
 284         ret = nouveau_framebuffer_new(dev, mode_cmd, nvbo, &fb);
 285         if (ret == 0)
 286                 return &fb->base;
 287 
 288         drm_gem_object_put_unlocked(gem);
 289         return ERR_PTR(ret);
 290 }
 291 
 292 static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
 293         .fb_create = nouveau_user_framebuffer_create,
 294         .output_poll_changed = nouveau_fbcon_output_poll_changed,
 295 };
 296 
 297 
 298 struct nouveau_drm_prop_enum_list {
 299         u8 gen_mask;
 300         int type;
 301         char *name;
 302 };
 303 
 304 static struct nouveau_drm_prop_enum_list underscan[] = {
 305         { 6, UNDERSCAN_AUTO, "auto" },
 306         { 6, UNDERSCAN_OFF, "off" },
 307         { 6, UNDERSCAN_ON, "on" },
 308         {}
 309 };
 310 
 311 static struct nouveau_drm_prop_enum_list dither_mode[] = {
 312         { 7, DITHERING_MODE_AUTO, "auto" },
 313         { 7, DITHERING_MODE_OFF, "off" },
 314         { 1, DITHERING_MODE_ON, "on" },
 315         { 6, DITHERING_MODE_STATIC2X2, "static 2x2" },
 316         { 6, DITHERING_MODE_DYNAMIC2X2, "dynamic 2x2" },
 317         { 4, DITHERING_MODE_TEMPORAL, "temporal" },
 318         {}
 319 };
 320 
 321 static struct nouveau_drm_prop_enum_list dither_depth[] = {
 322         { 6, DITHERING_DEPTH_AUTO, "auto" },
 323         { 6, DITHERING_DEPTH_6BPC, "6 bpc" },
 324         { 6, DITHERING_DEPTH_8BPC, "8 bpc" },
 325         {}
 326 };
 327 
 328 #define PROP_ENUM(p,gen,n,list) do {                                           \
 329         struct nouveau_drm_prop_enum_list *l = (list);                         \
 330         int c = 0;                                                             \
 331         while (l->gen_mask) {                                                  \
 332                 if (l->gen_mask & (1 << (gen)))                                \
 333                         c++;                                                   \
 334                 l++;                                                           \
 335         }                                                                      \
 336         if (c) {                                                               \
 337                 p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c);        \
 338                 l = (list);                                                    \
 339                 while (p && l->gen_mask) {                                     \
 340                         if (l->gen_mask & (1 << (gen))) {                      \
 341                                 drm_property_add_enum(p, l->type, l->name);    \
 342                         }                                                      \
 343                         l++;                                                   \
 344                 }                                                              \
 345         }                                                                      \
 346 } while(0)
 347 
 348 static void
 349 nouveau_display_hpd_work(struct work_struct *work)
 350 {
 351         struct nouveau_drm *drm = container_of(work, typeof(*drm), hpd_work);
 352 
 353         pm_runtime_get_sync(drm->dev->dev);
 354 
 355         drm_helper_hpd_irq_event(drm->dev);
 356 
 357         pm_runtime_mark_last_busy(drm->dev->dev);
 358         pm_runtime_put_sync(drm->dev->dev);
 359 }
 360 
 361 #ifdef CONFIG_ACPI
 362 
 363 static int
 364 nouveau_display_acpi_ntfy(struct notifier_block *nb, unsigned long val,
 365                           void *data)
 366 {
 367         struct nouveau_drm *drm = container_of(nb, typeof(*drm), acpi_nb);
 368         struct acpi_bus_event *info = data;
 369         int ret;
 370 
 371         if (!strcmp(info->device_class, ACPI_VIDEO_CLASS)) {
 372                 if (info->type == ACPI_VIDEO_NOTIFY_PROBE) {
 373                         ret = pm_runtime_get(drm->dev->dev);
 374                         if (ret == 1 || ret == -EACCES) {
 375                                 /* If the GPU is already awake, or in a state
 376                                  * where we can't wake it up, it can handle
 377                                  * it's own hotplug events.
 378                                  */
 379                                 pm_runtime_put_autosuspend(drm->dev->dev);
 380                         } else if (ret == 0) {
 381                                 /* This may be the only indication we receive
 382                                  * of a connector hotplug on a runtime
 383                                  * suspended GPU, schedule hpd_work to check.
 384                                  */
 385                                 NV_DEBUG(drm, "ACPI requested connector reprobe\n");
 386                                 schedule_work(&drm->hpd_work);
 387                                 pm_runtime_put_noidle(drm->dev->dev);
 388                         } else {
 389                                 NV_WARN(drm, "Dropped ACPI reprobe event due to RPM error: %d\n",
 390                                         ret);
 391                         }
 392 
 393                         /* acpi-video should not generate keypresses for this */
 394                         return NOTIFY_BAD;
 395                 }
 396         }
 397 
 398         return NOTIFY_DONE;
 399 }
 400 #endif
 401 
 402 int
 403 nouveau_display_init(struct drm_device *dev, bool resume, bool runtime)
 404 {
 405         struct nouveau_display *disp = nouveau_display(dev);
 406         struct drm_connector *connector;
 407         struct drm_connector_list_iter conn_iter;
 408         int ret;
 409 
 410         ret = disp->init(dev, resume, runtime);
 411         if (ret)
 412                 return ret;
 413 
 414         /* enable connector detection and polling for connectors without HPD
 415          * support
 416          */
 417         drm_kms_helper_poll_enable(dev);
 418 
 419         /* enable hotplug interrupts */
 420         drm_connector_list_iter_begin(dev, &conn_iter);
 421         nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
 422                 struct nouveau_connector *conn = nouveau_connector(connector);
 423                 nvif_notify_get(&conn->hpd);
 424         }
 425         drm_connector_list_iter_end(&conn_iter);
 426 
 427         return ret;
 428 }
 429 
 430 void
 431 nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
 432 {
 433         struct nouveau_display *disp = nouveau_display(dev);
 434         struct nouveau_drm *drm = nouveau_drm(dev);
 435         struct drm_connector *connector;
 436         struct drm_connector_list_iter conn_iter;
 437 
 438         if (!suspend) {
 439                 if (drm_drv_uses_atomic_modeset(dev))
 440                         drm_atomic_helper_shutdown(dev);
 441                 else
 442                         drm_helper_force_disable_all(dev);
 443         }
 444 
 445         /* disable hotplug interrupts */
 446         drm_connector_list_iter_begin(dev, &conn_iter);
 447         nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
 448                 struct nouveau_connector *conn = nouveau_connector(connector);
 449                 nvif_notify_put(&conn->hpd);
 450         }
 451         drm_connector_list_iter_end(&conn_iter);
 452 
 453         if (!runtime)
 454                 cancel_work_sync(&drm->hpd_work);
 455 
 456         drm_kms_helper_poll_disable(dev);
 457         disp->fini(dev, suspend);
 458 }
 459 
 460 static void
 461 nouveau_display_create_properties(struct drm_device *dev)
 462 {
 463         struct nouveau_display *disp = nouveau_display(dev);
 464         int gen;
 465 
 466         if (disp->disp.object.oclass < NV50_DISP)
 467                 gen = 0;
 468         else
 469         if (disp->disp.object.oclass < GF110_DISP)
 470                 gen = 1;
 471         else
 472                 gen = 2;
 473 
 474         PROP_ENUM(disp->dithering_mode, gen, "dithering mode", dither_mode);
 475         PROP_ENUM(disp->dithering_depth, gen, "dithering depth", dither_depth);
 476         PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
 477 
 478         disp->underscan_hborder_property =
 479                 drm_property_create_range(dev, 0, "underscan hborder", 0, 128);
 480 
 481         disp->underscan_vborder_property =
 482                 drm_property_create_range(dev, 0, "underscan vborder", 0, 128);
 483 
 484         if (gen < 1)
 485                 return;
 486 
 487         /* -90..+90 */
 488         disp->vibrant_hue_property =
 489                 drm_property_create_range(dev, 0, "vibrant hue", 0, 180);
 490 
 491         /* -100..+100 */
 492         disp->color_vibrance_property =
 493                 drm_property_create_range(dev, 0, "color vibrance", 0, 200);
 494 }
 495 
 496 int
 497 nouveau_display_create(struct drm_device *dev)
 498 {
 499         struct nouveau_drm *drm = nouveau_drm(dev);
 500         struct nvkm_device *device = nvxx_device(&drm->client.device);
 501         struct nouveau_display *disp;
 502         int ret;
 503 
 504         disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
 505         if (!disp)
 506                 return -ENOMEM;
 507 
 508         drm_mode_config_init(dev);
 509         drm_mode_create_scaling_mode_property(dev);
 510         drm_mode_create_dvi_i_properties(dev);
 511 
 512         dev->mode_config.funcs = &nouveau_mode_config_funcs;
 513         dev->mode_config.fb_base = device->func->resource_addr(device, 1);
 514 
 515         dev->mode_config.min_width = 0;
 516         dev->mode_config.min_height = 0;
 517         if (drm->client.device.info.family < NV_DEVICE_INFO_V0_CELSIUS) {
 518                 dev->mode_config.max_width = 2048;
 519                 dev->mode_config.max_height = 2048;
 520         } else
 521         if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
 522                 dev->mode_config.max_width = 4096;
 523                 dev->mode_config.max_height = 4096;
 524         } else
 525         if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) {
 526                 dev->mode_config.max_width = 8192;
 527                 dev->mode_config.max_height = 8192;
 528         } else {
 529                 dev->mode_config.max_width = 16384;
 530                 dev->mode_config.max_height = 16384;
 531         }
 532 
 533         dev->mode_config.preferred_depth = 24;
 534         dev->mode_config.prefer_shadow = 1;
 535 
 536         if (drm->client.device.info.chipset < 0x11)
 537                 dev->mode_config.async_page_flip = false;
 538         else
 539                 dev->mode_config.async_page_flip = true;
 540 
 541         drm_kms_helper_poll_init(dev);
 542         drm_kms_helper_poll_disable(dev);
 543 
 544         if (nouveau_modeset != 2 && drm->vbios.dcb.entries) {
 545                 ret = nvif_disp_ctor(&drm->client.device, 0, &disp->disp);
 546                 if (ret == 0) {
 547                         nouveau_display_create_properties(dev);
 548                         if (disp->disp.object.oclass < NV50_DISP)
 549                                 ret = nv04_display_create(dev);
 550                         else
 551                                 ret = nv50_display_create(dev);
 552                 }
 553         } else {
 554                 ret = 0;
 555         }
 556 
 557         if (ret)
 558                 goto disp_create_err;
 559 
 560         drm_mode_config_reset(dev);
 561 
 562         if (dev->mode_config.num_crtc) {
 563                 ret = nouveau_display_vblank_init(dev);
 564                 if (ret)
 565                         goto vblank_err;
 566         }
 567 
 568         INIT_WORK(&drm->hpd_work, nouveau_display_hpd_work);
 569 #ifdef CONFIG_ACPI
 570         drm->acpi_nb.notifier_call = nouveau_display_acpi_ntfy;
 571         register_acpi_notifier(&drm->acpi_nb);
 572 #endif
 573 
 574         return 0;
 575 
 576 vblank_err:
 577         disp->dtor(dev);
 578 disp_create_err:
 579         drm_kms_helper_poll_fini(dev);
 580         drm_mode_config_cleanup(dev);
 581         return ret;
 582 }
 583 
 584 void
 585 nouveau_display_destroy(struct drm_device *dev)
 586 {
 587         struct nouveau_display *disp = nouveau_display(dev);
 588 
 589 #ifdef CONFIG_ACPI
 590         unregister_acpi_notifier(&nouveau_drm(dev)->acpi_nb);
 591 #endif
 592         nouveau_display_vblank_fini(dev);
 593 
 594         drm_kms_helper_poll_fini(dev);
 595         drm_mode_config_cleanup(dev);
 596 
 597         if (disp->dtor)
 598                 disp->dtor(dev);
 599 
 600         nvif_disp_dtor(&disp->disp);
 601 
 602         nouveau_drm(dev)->display = NULL;
 603         kfree(disp);
 604 }
 605 
 606 int
 607 nouveau_display_suspend(struct drm_device *dev, bool runtime)
 608 {
 609         struct nouveau_display *disp = nouveau_display(dev);
 610 
 611         if (drm_drv_uses_atomic_modeset(dev)) {
 612                 if (!runtime) {
 613                         disp->suspend = drm_atomic_helper_suspend(dev);
 614                         if (IS_ERR(disp->suspend)) {
 615                                 int ret = PTR_ERR(disp->suspend);
 616                                 disp->suspend = NULL;
 617                                 return ret;
 618                         }
 619                 }
 620         }
 621 
 622         nouveau_display_fini(dev, true, runtime);
 623         return 0;
 624 }
 625 
 626 void
 627 nouveau_display_resume(struct drm_device *dev, bool runtime)
 628 {
 629         struct nouveau_display *disp = nouveau_display(dev);
 630 
 631         nouveau_display_init(dev, true, runtime);
 632 
 633         if (drm_drv_uses_atomic_modeset(dev)) {
 634                 if (disp->suspend) {
 635                         drm_atomic_helper_resume(dev, disp->suspend);
 636                         disp->suspend = NULL;
 637                 }
 638                 return;
 639         }
 640 }
 641 
 642 int
 643 nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
 644                             struct drm_mode_create_dumb *args)
 645 {
 646         struct nouveau_cli *cli = nouveau_cli(file_priv);
 647         struct nouveau_bo *bo;
 648         uint32_t domain;
 649         int ret;
 650 
 651         args->pitch = roundup(args->width * (args->bpp / 8), 256);
 652         args->size = args->pitch * args->height;
 653         args->size = roundup(args->size, PAGE_SIZE);
 654 
 655         /* Use VRAM if there is any ; otherwise fallback to system memory */
 656         if (nouveau_drm(dev)->client.device.info.ram_size != 0)
 657                 domain = NOUVEAU_GEM_DOMAIN_VRAM;
 658         else
 659                 domain = NOUVEAU_GEM_DOMAIN_GART;
 660 
 661         ret = nouveau_gem_new(cli, args->size, 0, domain, 0, 0, &bo);
 662         if (ret)
 663                 return ret;
 664 
 665         ret = drm_gem_handle_create(file_priv, &bo->bo.base, &args->handle);
 666         drm_gem_object_put_unlocked(&bo->bo.base);
 667         return ret;
 668 }
 669 
 670 int
 671 nouveau_display_dumb_map_offset(struct drm_file *file_priv,
 672                                 struct drm_device *dev,
 673                                 uint32_t handle, uint64_t *poffset)
 674 {
 675         struct drm_gem_object *gem;
 676 
 677         gem = drm_gem_object_lookup(file_priv, handle);
 678         if (gem) {
 679                 struct nouveau_bo *bo = nouveau_gem_object(gem);
 680                 *poffset = drm_vma_node_offset_addr(&bo->bo.base.vma_node);
 681                 drm_gem_object_put_unlocked(gem);
 682                 return 0;
 683         }
 684 
 685         return -ENOENT;
 686 }

/* [<][>][^][v][top][bottom][index][help] */