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