0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include <acpi/video.h>
0028
0029 #include <drm/drm_atomic.h>
0030 #include <drm/drm_atomic_helper.h>
0031 #include <drm/drm_crtc_helper.h>
0032 #include <drm/drm_fb_helper.h>
0033 #include <drm/drm_fourcc.h>
0034 #include <drm/drm_gem_framebuffer_helper.h>
0035 #include <drm/drm_probe_helper.h>
0036 #include <drm/drm_vblank.h>
0037
0038 #include "nouveau_fbcon.h"
0039 #include "nouveau_crtc.h"
0040 #include "nouveau_gem.h"
0041 #include "nouveau_connector.h"
0042 #include "nv50_display.h"
0043
0044 #include <nvif/class.h>
0045 #include <nvif/cl0046.h>
0046 #include <nvif/event.h>
0047 #include <dispnv50/crc.h>
0048
0049 int
0050 nouveau_display_vblank_enable(struct drm_crtc *crtc)
0051 {
0052 struct nouveau_crtc *nv_crtc;
0053
0054 nv_crtc = nouveau_crtc(crtc);
0055 nvif_notify_get(&nv_crtc->vblank);
0056
0057 return 0;
0058 }
0059
0060 void
0061 nouveau_display_vblank_disable(struct drm_crtc *crtc)
0062 {
0063 struct nouveau_crtc *nv_crtc;
0064
0065 nv_crtc = nouveau_crtc(crtc);
0066 nvif_notify_put(&nv_crtc->vblank);
0067 }
0068
0069 static inline int
0070 calc(int blanks, int blanke, int total, int line)
0071 {
0072 if (blanke >= blanks) {
0073 if (line >= blanks)
0074 line -= total;
0075 } else {
0076 if (line >= blanks)
0077 line -= total;
0078 line -= blanke + 1;
0079 }
0080 return line;
0081 }
0082
0083 static bool
0084 nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
0085 ktime_t *stime, ktime_t *etime)
0086 {
0087 struct {
0088 struct nv04_disp_mthd_v0 base;
0089 struct nv04_disp_scanoutpos_v0 scan;
0090 } args = {
0091 .base.method = NV04_DISP_SCANOUTPOS,
0092 .base.head = nouveau_crtc(crtc)->index,
0093 };
0094 struct nouveau_display *disp = nouveau_display(crtc->dev);
0095 struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
0096 int retry = 20;
0097 bool ret = false;
0098
0099 do {
0100 ret = nvif_mthd(&disp->disp.object, 0, &args, sizeof(args));
0101 if (ret != 0)
0102 return false;
0103
0104 if (args.scan.vline) {
0105 ret = true;
0106 break;
0107 }
0108
0109 if (retry) ndelay(vblank->linedur_ns);
0110 } while (retry--);
0111
0112 *hpos = args.scan.hline;
0113 *vpos = calc(args.scan.vblanks, args.scan.vblanke,
0114 args.scan.vtotal, args.scan.vline);
0115 if (stime) *stime = ns_to_ktime(args.scan.time[0]);
0116 if (etime) *etime = ns_to_ktime(args.scan.time[1]);
0117
0118 return ret;
0119 }
0120
0121 bool
0122 nouveau_display_scanoutpos(struct drm_crtc *crtc,
0123 bool in_vblank_irq, int *vpos, int *hpos,
0124 ktime_t *stime, ktime_t *etime,
0125 const struct drm_display_mode *mode)
0126 {
0127 return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
0128 stime, etime);
0129 }
0130
0131 static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
0132 .destroy = drm_gem_fb_destroy,
0133 .create_handle = drm_gem_fb_create_handle,
0134 };
0135
0136 static void
0137 nouveau_decode_mod(struct nouveau_drm *drm,
0138 uint64_t modifier,
0139 uint32_t *tile_mode,
0140 uint8_t *kind)
0141 {
0142 struct nouveau_display *disp = nouveau_display(drm->dev);
0143 BUG_ON(!tile_mode || !kind);
0144
0145 if (modifier == DRM_FORMAT_MOD_LINEAR) {
0146
0147 *tile_mode = 0;
0148 *kind = 0;
0149 } else {
0150
0151
0152
0153
0154
0155 if ((modifier & (0xffull << 12)) == 0ull) {
0156
0157 modifier |= disp->format_modifiers[0] & (0xffull << 12);
0158 }
0159
0160 *tile_mode = (uint32_t)(modifier & 0xF);
0161 *kind = (uint8_t)((modifier >> 12) & 0xFF);
0162
0163 if (drm->client.device.info.chipset >= 0xc0)
0164 *tile_mode <<= 4;
0165 }
0166 }
0167
0168 void
0169 nouveau_framebuffer_get_layout(struct drm_framebuffer *fb,
0170 uint32_t *tile_mode,
0171 uint8_t *kind)
0172 {
0173 if (fb->flags & DRM_MODE_FB_MODIFIERS) {
0174 struct nouveau_drm *drm = nouveau_drm(fb->dev);
0175
0176 nouveau_decode_mod(drm, fb->modifier, tile_mode, kind);
0177 } else {
0178 const struct nouveau_bo *nvbo = nouveau_gem_object(fb->obj[0]);
0179
0180 *tile_mode = nvbo->mode;
0181 *kind = nvbo->kind;
0182 }
0183 }
0184
0185 static const u64 legacy_modifiers[] = {
0186 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0),
0187 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1),
0188 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2),
0189 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3),
0190 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4),
0191 DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5),
0192 DRM_FORMAT_MOD_INVALID
0193 };
0194
0195 static int
0196 nouveau_validate_decode_mod(struct nouveau_drm *drm,
0197 uint64_t modifier,
0198 uint32_t *tile_mode,
0199 uint8_t *kind)
0200 {
0201 struct nouveau_display *disp = nouveau_display(drm->dev);
0202 int mod;
0203
0204 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
0205 return -EINVAL;
0206 }
0207
0208 BUG_ON(!disp->format_modifiers);
0209
0210 for (mod = 0;
0211 (disp->format_modifiers[mod] != DRM_FORMAT_MOD_INVALID) &&
0212 (disp->format_modifiers[mod] != modifier);
0213 mod++);
0214
0215 if (disp->format_modifiers[mod] == DRM_FORMAT_MOD_INVALID) {
0216 for (mod = 0;
0217 (legacy_modifiers[mod] != DRM_FORMAT_MOD_INVALID) &&
0218 (legacy_modifiers[mod] != modifier);
0219 mod++);
0220 if (legacy_modifiers[mod] == DRM_FORMAT_MOD_INVALID)
0221 return -EINVAL;
0222 }
0223
0224 nouveau_decode_mod(drm, modifier, tile_mode, kind);
0225
0226 return 0;
0227 }
0228
0229 static inline uint32_t
0230 nouveau_get_width_in_blocks(uint32_t stride)
0231 {
0232
0233
0234
0235 static const uint32_t log_block_width = 6;
0236
0237 return (stride + (1 << log_block_width) - 1) >> log_block_width;
0238 }
0239
0240 static inline uint32_t
0241 nouveau_get_height_in_blocks(struct nouveau_drm *drm,
0242 uint32_t height,
0243 uint32_t log_block_height_in_gobs)
0244 {
0245 uint32_t log_gob_height;
0246 uint32_t log_block_height;
0247
0248 BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA);
0249
0250 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI)
0251 log_gob_height = 2;
0252 else
0253 log_gob_height = 3;
0254
0255 log_block_height = log_block_height_in_gobs + log_gob_height;
0256
0257 return (height + (1 << log_block_height) - 1) >> log_block_height;
0258 }
0259
0260 static int
0261 nouveau_check_bl_size(struct nouveau_drm *drm, struct nouveau_bo *nvbo,
0262 uint32_t offset, uint32_t stride, uint32_t h,
0263 uint32_t tile_mode)
0264 {
0265 uint32_t gob_size, bw, bh;
0266 uint64_t bl_size;
0267
0268 BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA);
0269
0270 if (drm->client.device.info.chipset >= 0xc0) {
0271 if (tile_mode & 0xF)
0272 return -EINVAL;
0273 tile_mode >>= 4;
0274 }
0275
0276 if (tile_mode & 0xFFFFFFF0)
0277 return -EINVAL;
0278
0279 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI)
0280 gob_size = 256;
0281 else
0282 gob_size = 512;
0283
0284 bw = nouveau_get_width_in_blocks(stride);
0285 bh = nouveau_get_height_in_blocks(drm, h, tile_mode);
0286
0287 bl_size = bw * bh * (1 << tile_mode) * gob_size;
0288
0289 DRM_DEBUG_KMS("offset=%u stride=%u h=%u tile_mode=0x%02x bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n",
0290 offset, stride, h, tile_mode, bw, bh, gob_size, bl_size,
0291 nvbo->bo.base.size);
0292
0293 if (bl_size + offset > nvbo->bo.base.size)
0294 return -ERANGE;
0295
0296 return 0;
0297 }
0298
0299 int
0300 nouveau_framebuffer_new(struct drm_device *dev,
0301 const struct drm_mode_fb_cmd2 *mode_cmd,
0302 struct drm_gem_object *gem,
0303 struct drm_framebuffer **pfb)
0304 {
0305 struct nouveau_drm *drm = nouveau_drm(dev);
0306 struct nouveau_bo *nvbo = nouveau_gem_object(gem);
0307 struct drm_framebuffer *fb;
0308 const struct drm_format_info *info;
0309 unsigned int height, i;
0310 uint32_t tile_mode;
0311 uint8_t kind;
0312 int ret;
0313
0314
0315 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA &&
0316
0317 (mode_cmd->pixel_format == DRM_FORMAT_YUYV ||
0318 mode_cmd->pixel_format == DRM_FORMAT_UYVY ||
0319 mode_cmd->pixel_format == DRM_FORMAT_NV12 ||
0320 mode_cmd->pixel_format == DRM_FORMAT_NV21) &&
0321 (mode_cmd->pitches[0] & 0x3f ||
0322 mode_cmd->pitches[0] >= 0x10000 ||
0323 (mode_cmd->pitches[1] &&
0324 mode_cmd->pitches[0] != mode_cmd->pitches[1]))) {
0325 DRM_DEBUG_KMS("Unsuitable framebuffer: format: %p4cc; pitches: 0x%x\n 0x%x\n",
0326 &mode_cmd->pixel_format,
0327 mode_cmd->pitches[0], mode_cmd->pitches[1]);
0328 return -EINVAL;
0329 }
0330
0331 if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
0332 if (nouveau_validate_decode_mod(drm, mode_cmd->modifier[0],
0333 &tile_mode, &kind)) {
0334 DRM_DEBUG_KMS("Unsupported modifier: 0x%llx\n",
0335 mode_cmd->modifier[0]);
0336 return -EINVAL;
0337 }
0338 } else {
0339 tile_mode = nvbo->mode;
0340 kind = nvbo->kind;
0341 }
0342
0343 info = drm_get_format_info(dev, mode_cmd);
0344
0345 for (i = 0; i < info->num_planes; i++) {
0346 height = drm_format_info_plane_height(info,
0347 mode_cmd->height,
0348 i);
0349
0350 if (kind) {
0351 ret = nouveau_check_bl_size(drm, nvbo,
0352 mode_cmd->offsets[i],
0353 mode_cmd->pitches[i],
0354 height, tile_mode);
0355 if (ret)
0356 return ret;
0357 } else {
0358 uint32_t size = mode_cmd->pitches[i] * height;
0359
0360 if (size + mode_cmd->offsets[i] > nvbo->bo.base.size)
0361 return -ERANGE;
0362 }
0363 }
0364
0365 if (!(fb = *pfb = kzalloc(sizeof(*fb), GFP_KERNEL)))
0366 return -ENOMEM;
0367
0368 drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
0369 fb->obj[0] = gem;
0370
0371 ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
0372 if (ret)
0373 kfree(fb);
0374 return ret;
0375 }
0376
0377 struct drm_framebuffer *
0378 nouveau_user_framebuffer_create(struct drm_device *dev,
0379 struct drm_file *file_priv,
0380 const struct drm_mode_fb_cmd2 *mode_cmd)
0381 {
0382 struct drm_framebuffer *fb;
0383 struct drm_gem_object *gem;
0384 int ret;
0385
0386 gem = drm_gem_object_lookup(file_priv, mode_cmd->handles[0]);
0387 if (!gem)
0388 return ERR_PTR(-ENOENT);
0389
0390 ret = nouveau_framebuffer_new(dev, mode_cmd, gem, &fb);
0391 if (ret == 0)
0392 return fb;
0393
0394 drm_gem_object_put(gem);
0395 return ERR_PTR(ret);
0396 }
0397
0398 static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
0399 .fb_create = nouveau_user_framebuffer_create,
0400 .output_poll_changed = nouveau_fbcon_output_poll_changed,
0401 };
0402
0403
0404 struct nouveau_drm_prop_enum_list {
0405 u8 gen_mask;
0406 int type;
0407 char *name;
0408 };
0409
0410 static struct nouveau_drm_prop_enum_list underscan[] = {
0411 { 6, UNDERSCAN_AUTO, "auto" },
0412 { 6, UNDERSCAN_OFF, "off" },
0413 { 6, UNDERSCAN_ON, "on" },
0414 {}
0415 };
0416
0417 static struct nouveau_drm_prop_enum_list dither_mode[] = {
0418 { 7, DITHERING_MODE_AUTO, "auto" },
0419 { 7, DITHERING_MODE_OFF, "off" },
0420 { 1, DITHERING_MODE_ON, "on" },
0421 { 6, DITHERING_MODE_STATIC2X2, "static 2x2" },
0422 { 6, DITHERING_MODE_DYNAMIC2X2, "dynamic 2x2" },
0423 { 4, DITHERING_MODE_TEMPORAL, "temporal" },
0424 {}
0425 };
0426
0427 static struct nouveau_drm_prop_enum_list dither_depth[] = {
0428 { 6, DITHERING_DEPTH_AUTO, "auto" },
0429 { 6, DITHERING_DEPTH_6BPC, "6 bpc" },
0430 { 6, DITHERING_DEPTH_8BPC, "8 bpc" },
0431 {}
0432 };
0433
0434 #define PROP_ENUM(p,gen,n,list) do { \
0435 struct nouveau_drm_prop_enum_list *l = (list); \
0436 int c = 0; \
0437 while (l->gen_mask) { \
0438 if (l->gen_mask & (1 << (gen))) \
0439 c++; \
0440 l++; \
0441 } \
0442 if (c) { \
0443 p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c); \
0444 l = (list); \
0445 while (p && l->gen_mask) { \
0446 if (l->gen_mask & (1 << (gen))) { \
0447 drm_property_add_enum(p, l->type, l->name); \
0448 } \
0449 l++; \
0450 } \
0451 } \
0452 } while(0)
0453
0454 void
0455 nouveau_display_hpd_resume(struct drm_device *dev)
0456 {
0457 struct nouveau_drm *drm = nouveau_drm(dev);
0458
0459 mutex_lock(&drm->hpd_lock);
0460 drm->hpd_pending = ~0;
0461 mutex_unlock(&drm->hpd_lock);
0462
0463 schedule_work(&drm->hpd_work);
0464 }
0465
0466 static void
0467 nouveau_display_hpd_work(struct work_struct *work)
0468 {
0469 struct nouveau_drm *drm = container_of(work, typeof(*drm), hpd_work);
0470 struct drm_device *dev = drm->dev;
0471 struct drm_connector *connector;
0472 struct drm_connector_list_iter conn_iter;
0473 u32 pending;
0474 bool changed = false;
0475
0476 pm_runtime_get_sync(dev->dev);
0477
0478 mutex_lock(&drm->hpd_lock);
0479 pending = drm->hpd_pending;
0480 drm->hpd_pending = 0;
0481 mutex_unlock(&drm->hpd_lock);
0482
0483
0484 if (!pending)
0485 goto noop;
0486
0487 mutex_lock(&dev->mode_config.mutex);
0488 drm_connector_list_iter_begin(dev, &conn_iter);
0489
0490 nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
0491 enum drm_connector_status old_status = connector->status;
0492 u64 old_epoch_counter = connector->epoch_counter;
0493
0494 if (!(pending & drm_connector_mask(connector)))
0495 continue;
0496
0497 connector->status = drm_helper_probe_detect(connector, NULL,
0498 false);
0499 if (old_epoch_counter == connector->epoch_counter)
0500 continue;
0501
0502 changed = true;
0503 drm_dbg_kms(dev, "[CONNECTOR:%d:%s] status updated from %s to %s (epoch counter %llu->%llu)\n",
0504 connector->base.id, connector->name,
0505 drm_get_connector_status_name(old_status),
0506 drm_get_connector_status_name(connector->status),
0507 old_epoch_counter, connector->epoch_counter);
0508 }
0509
0510 drm_connector_list_iter_end(&conn_iter);
0511 mutex_unlock(&dev->mode_config.mutex);
0512
0513 if (changed)
0514 drm_kms_helper_hotplug_event(dev);
0515
0516 pm_runtime_mark_last_busy(drm->dev->dev);
0517 noop:
0518 pm_runtime_put_autosuspend(dev->dev);
0519 }
0520
0521 #ifdef CONFIG_ACPI
0522
0523 static int
0524 nouveau_display_acpi_ntfy(struct notifier_block *nb, unsigned long val,
0525 void *data)
0526 {
0527 struct nouveau_drm *drm = container_of(nb, typeof(*drm), acpi_nb);
0528 struct acpi_bus_event *info = data;
0529 int ret;
0530
0531 if (!strcmp(info->device_class, ACPI_VIDEO_CLASS)) {
0532 if (info->type == ACPI_VIDEO_NOTIFY_PROBE) {
0533 ret = pm_runtime_get(drm->dev->dev);
0534 if (ret == 1 || ret == -EACCES) {
0535
0536
0537
0538
0539 pm_runtime_put_autosuspend(drm->dev->dev);
0540 } else if (ret == 0 || ret == -EINPROGRESS) {
0541
0542
0543
0544
0545 NV_DEBUG(drm, "ACPI requested connector reprobe\n");
0546 pm_runtime_put_noidle(drm->dev->dev);
0547 } else {
0548 NV_WARN(drm, "Dropped ACPI reprobe event due to RPM error: %d\n",
0549 ret);
0550 }
0551
0552
0553 return NOTIFY_BAD;
0554 }
0555 }
0556
0557 return NOTIFY_DONE;
0558 }
0559 #endif
0560
0561 int
0562 nouveau_display_init(struct drm_device *dev, bool resume, bool runtime)
0563 {
0564 struct nouveau_display *disp = nouveau_display(dev);
0565 struct drm_connector *connector;
0566 struct drm_connector_list_iter conn_iter;
0567 int ret;
0568
0569
0570
0571
0572
0573 drm_connector_list_iter_begin(dev, &conn_iter);
0574 nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
0575 struct nouveau_connector *conn = nouveau_connector(connector);
0576 nvif_notify_get(&conn->hpd);
0577 }
0578 drm_connector_list_iter_end(&conn_iter);
0579
0580 ret = disp->init(dev, resume, runtime);
0581 if (ret)
0582 return ret;
0583
0584
0585
0586
0587 drm_kms_helper_poll_enable(dev);
0588
0589 return ret;
0590 }
0591
0592 void
0593 nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
0594 {
0595 struct nouveau_display *disp = nouveau_display(dev);
0596 struct nouveau_drm *drm = nouveau_drm(dev);
0597 struct drm_connector *connector;
0598 struct drm_connector_list_iter conn_iter;
0599
0600 if (!suspend) {
0601 if (drm_drv_uses_atomic_modeset(dev))
0602 drm_atomic_helper_shutdown(dev);
0603 else
0604 drm_helper_force_disable_all(dev);
0605 }
0606
0607
0608 drm_connector_list_iter_begin(dev, &conn_iter);
0609 nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
0610 struct nouveau_connector *conn = nouveau_connector(connector);
0611 nvif_notify_put(&conn->hpd);
0612 }
0613 drm_connector_list_iter_end(&conn_iter);
0614
0615 if (!runtime)
0616 cancel_work_sync(&drm->hpd_work);
0617
0618 drm_kms_helper_poll_disable(dev);
0619 disp->fini(dev, runtime, suspend);
0620 }
0621
0622 static void
0623 nouveau_display_create_properties(struct drm_device *dev)
0624 {
0625 struct nouveau_display *disp = nouveau_display(dev);
0626 int gen;
0627
0628 if (disp->disp.object.oclass < NV50_DISP)
0629 gen = 0;
0630 else
0631 if (disp->disp.object.oclass < GF110_DISP)
0632 gen = 1;
0633 else
0634 gen = 2;
0635
0636 PROP_ENUM(disp->dithering_mode, gen, "dithering mode", dither_mode);
0637 PROP_ENUM(disp->dithering_depth, gen, "dithering depth", dither_depth);
0638 PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
0639
0640 disp->underscan_hborder_property =
0641 drm_property_create_range(dev, 0, "underscan hborder", 0, 128);
0642
0643 disp->underscan_vborder_property =
0644 drm_property_create_range(dev, 0, "underscan vborder", 0, 128);
0645
0646 if (gen < 1)
0647 return;
0648
0649
0650 disp->vibrant_hue_property =
0651 drm_property_create_range(dev, 0, "vibrant hue", 0, 180);
0652
0653
0654 disp->color_vibrance_property =
0655 drm_property_create_range(dev, 0, "color vibrance", 0, 200);
0656 }
0657
0658 int
0659 nouveau_display_create(struct drm_device *dev)
0660 {
0661 struct nouveau_drm *drm = nouveau_drm(dev);
0662 struct nvkm_device *device = nvxx_device(&drm->client.device);
0663 struct nouveau_display *disp;
0664 int ret;
0665
0666 disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
0667 if (!disp)
0668 return -ENOMEM;
0669
0670 drm_mode_config_init(dev);
0671 drm_mode_create_scaling_mode_property(dev);
0672 drm_mode_create_dvi_i_properties(dev);
0673
0674 dev->mode_config.funcs = &nouveau_mode_config_funcs;
0675 dev->mode_config.fb_base = device->func->resource_addr(device, 1);
0676
0677 dev->mode_config.min_width = 0;
0678 dev->mode_config.min_height = 0;
0679 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_CELSIUS) {
0680 dev->mode_config.max_width = 2048;
0681 dev->mode_config.max_height = 2048;
0682 } else
0683 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
0684 dev->mode_config.max_width = 4096;
0685 dev->mode_config.max_height = 4096;
0686 } else
0687 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) {
0688 dev->mode_config.max_width = 8192;
0689 dev->mode_config.max_height = 8192;
0690 } else {
0691 dev->mode_config.max_width = 16384;
0692 dev->mode_config.max_height = 16384;
0693 }
0694
0695 dev->mode_config.preferred_depth = 24;
0696 dev->mode_config.prefer_shadow = 1;
0697
0698 if (drm->client.device.info.chipset < 0x11)
0699 dev->mode_config.async_page_flip = false;
0700 else
0701 dev->mode_config.async_page_flip = true;
0702
0703 drm_kms_helper_poll_init(dev);
0704 drm_kms_helper_poll_disable(dev);
0705
0706 if (nouveau_modeset != 2 && drm->vbios.dcb.entries) {
0707 ret = nvif_disp_ctor(&drm->client.device, "kmsDisp", 0,
0708 &disp->disp);
0709 if (ret == 0) {
0710 nouveau_display_create_properties(dev);
0711 if (disp->disp.object.oclass < NV50_DISP) {
0712 dev->mode_config.fb_modifiers_not_supported = true;
0713 ret = nv04_display_create(dev);
0714 } else {
0715 ret = nv50_display_create(dev);
0716 }
0717 }
0718 } else {
0719 ret = 0;
0720 }
0721
0722 if (ret)
0723 goto disp_create_err;
0724
0725 drm_mode_config_reset(dev);
0726
0727 if (dev->mode_config.num_crtc) {
0728 ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
0729 if (ret)
0730 goto vblank_err;
0731
0732 if (disp->disp.object.oclass >= NV50_DISP)
0733 nv50_crc_init(dev);
0734 }
0735
0736 INIT_WORK(&drm->hpd_work, nouveau_display_hpd_work);
0737 mutex_init(&drm->hpd_lock);
0738 #ifdef CONFIG_ACPI
0739 drm->acpi_nb.notifier_call = nouveau_display_acpi_ntfy;
0740 register_acpi_notifier(&drm->acpi_nb);
0741 #endif
0742
0743 return 0;
0744
0745 vblank_err:
0746 disp->dtor(dev);
0747 disp_create_err:
0748 drm_kms_helper_poll_fini(dev);
0749 drm_mode_config_cleanup(dev);
0750 return ret;
0751 }
0752
0753 void
0754 nouveau_display_destroy(struct drm_device *dev)
0755 {
0756 struct nouveau_display *disp = nouveau_display(dev);
0757 struct nouveau_drm *drm = nouveau_drm(dev);
0758
0759 #ifdef CONFIG_ACPI
0760 unregister_acpi_notifier(&drm->acpi_nb);
0761 #endif
0762
0763 drm_kms_helper_poll_fini(dev);
0764 drm_mode_config_cleanup(dev);
0765
0766 if (disp->dtor)
0767 disp->dtor(dev);
0768
0769 nvif_disp_dtor(&disp->disp);
0770
0771 nouveau_drm(dev)->display = NULL;
0772 mutex_destroy(&drm->hpd_lock);
0773 kfree(disp);
0774 }
0775
0776 int
0777 nouveau_display_suspend(struct drm_device *dev, bool runtime)
0778 {
0779 struct nouveau_display *disp = nouveau_display(dev);
0780
0781 if (drm_drv_uses_atomic_modeset(dev)) {
0782 if (!runtime) {
0783 disp->suspend = drm_atomic_helper_suspend(dev);
0784 if (IS_ERR(disp->suspend)) {
0785 int ret = PTR_ERR(disp->suspend);
0786 disp->suspend = NULL;
0787 return ret;
0788 }
0789 }
0790 }
0791
0792 nouveau_display_fini(dev, true, runtime);
0793 return 0;
0794 }
0795
0796 void
0797 nouveau_display_resume(struct drm_device *dev, bool runtime)
0798 {
0799 struct nouveau_display *disp = nouveau_display(dev);
0800
0801 nouveau_display_init(dev, true, runtime);
0802
0803 if (drm_drv_uses_atomic_modeset(dev)) {
0804 if (disp->suspend) {
0805 drm_atomic_helper_resume(dev, disp->suspend);
0806 disp->suspend = NULL;
0807 }
0808 return;
0809 }
0810 }
0811
0812 int
0813 nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
0814 struct drm_mode_create_dumb *args)
0815 {
0816 struct nouveau_cli *cli = nouveau_cli(file_priv);
0817 struct nouveau_bo *bo;
0818 uint32_t domain;
0819 int ret;
0820
0821 args->pitch = roundup(args->width * (args->bpp / 8), 256);
0822 args->size = args->pitch * args->height;
0823 args->size = roundup(args->size, PAGE_SIZE);
0824
0825
0826 if (nouveau_drm(dev)->client.device.info.ram_size != 0)
0827 domain = NOUVEAU_GEM_DOMAIN_VRAM;
0828 else
0829 domain = NOUVEAU_GEM_DOMAIN_GART;
0830
0831 ret = nouveau_gem_new(cli, args->size, 0, domain, 0, 0, &bo);
0832 if (ret)
0833 return ret;
0834
0835 ret = drm_gem_handle_create(file_priv, &bo->bo.base, &args->handle);
0836 drm_gem_object_put(&bo->bo.base);
0837 return ret;
0838 }