1/* $NetBSD: nouveau_dispnv04_disp.c,v 1.6 2021/12/18 23:45:32 riastradh Exp $ */ 2 3/* 4 * Copyright 2009 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Author: Ben Skeggs 25 */ 26 27#include <sys/cdefs.h> 28__KERNEL_RCSID(0, "$NetBSD: nouveau_dispnv04_disp.c,v 1.6 2021/12/18 23:45:32 riastradh Exp $"); 29 30#include <drm/drm_crtc_helper.h> 31 32#include "nouveau_drv.h" 33#include "nouveau_reg.h" 34#include "hw.h" 35#include "nouveau_encoder.h" 36#include "nouveau_connector.h" 37#include "nouveau_bo.h" 38 39#include <nvif/if0004.h> 40 41static void 42nv04_display_fini(struct drm_device *dev, bool suspend) 43{ 44 struct nv04_display *disp = nv04_display(dev); 45 struct drm_crtc *crtc; 46 47 /* Disable flip completion events. */ 48 nvif_notify_put(&disp->flip); 49 50 /* Disable vblank interrupts. */ 51 NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0); 52 if (nv_two_heads(dev)) 53 NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0); 54 55 if (!suspend) 56 return; 57 58 /* Un-pin FB and cursors so they'll be evicted to system memory. */ 59 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 60 struct nouveau_framebuffer *nouveau_fb; 61 62 nouveau_fb = nouveau_framebuffer(crtc->primary->fb); 63 if (!nouveau_fb || !nouveau_fb->nvbo) 64 continue; 65 66 nouveau_bo_unpin(nouveau_fb->nvbo); 67 } 68 69 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 70 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 71 if (nv_crtc->cursor.nvbo) { 72 if (nv_crtc->cursor.set_offset) 73 nouveau_bo_unmap(nv_crtc->cursor.nvbo); 74 nouveau_bo_unpin(nv_crtc->cursor.nvbo); 75 } 76 } 77} 78 79static int 80nv04_display_init(struct drm_device *dev, bool resume, bool runtime) 81{ 82 struct nv04_display *disp = nv04_display(dev); 83 struct nouveau_drm *drm = nouveau_drm(dev); 84 struct nouveau_encoder *encoder; 85 struct drm_crtc *crtc; 86 int ret; 87 88 /* meh.. modeset apparently doesn't setup all the regs and depends 89 * on pre-existing state, for now load the state of the card *before* 90 * nouveau was loaded, and then do a modeset. 91 * 92 * best thing to do probably is to make save/restore routines not 93 * save/restore "pre-load" state, but more general so we can save 94 * on suspend too. 95 */ 96 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 97 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 98 nv_crtc->save(&nv_crtc->base); 99 } 100 101 list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head) 102 encoder->enc_save(&encoder->base.base); 103 104 /* Enable flip completion events. */ 105 nvif_notify_get(&disp->flip); 106 107 if (!resume) 108 return 0; 109 110 /* Re-pin FB/cursors. */ 111 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 112 struct nouveau_framebuffer *nouveau_fb; 113 114 nouveau_fb = nouveau_framebuffer(crtc->primary->fb); 115 if (!nouveau_fb || !nouveau_fb->nvbo) 116 continue; 117 118 ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM, true); 119 if (ret) 120 NV_ERROR(drm, "Could not pin framebuffer\n"); 121 } 122 123 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 124 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 125 if (!nv_crtc->cursor.nvbo) 126 continue; 127 128 ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, true); 129 if (!ret && nv_crtc->cursor.set_offset) 130 ret = nouveau_bo_map(nv_crtc->cursor.nvbo); 131 if (ret) 132 NV_ERROR(drm, "Could not pin/map cursor.\n"); 133 } 134 135 /* Force CLUT to get re-loaded during modeset. */ 136 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 137 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 138 139 nv_crtc->lut.depth = 0; 140 } 141 142 /* This should ensure we don't hit a locking problem when someone 143 * wakes us up via a connector. We should never go into suspend 144 * while the display is on anyways. 145 */ 146 if (runtime) 147 return 0; 148 149 /* Restore mode. */ 150 drm_helper_resume_force_mode(dev); 151 152 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 153 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 154 155 if (!nv_crtc->cursor.nvbo) 156 continue; 157 158 if (nv_crtc->cursor.set_offset) 159 nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset); 160 nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x, 161 nv_crtc->cursor_saved_y); 162 } 163 164 return 0; 165} 166 167static void 168nv04_display_destroy(struct drm_device *dev) 169{ 170 struct nv04_display *disp = nv04_display(dev); 171 struct nouveau_drm *drm = nouveau_drm(dev); 172 struct nouveau_encoder *encoder; 173 struct nouveau_crtc *nv_crtc; 174 175 /* Restore state */ 176 list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head) 177 encoder->enc_restore(&encoder->base.base); 178 179 list_for_each_entry(nv_crtc, &dev->mode_config.crtc_list, base.head) 180 nv_crtc->restore(&nv_crtc->base); 181 182 nouveau_hw_save_vga_fonts(dev, 0); 183 184 nvif_notify_fini(&disp->flip); 185 186 nouveau_display(dev)->priv = NULL; 187 kfree(disp); 188 189 nvif_object_unmap(&drm->client.device.object); 190} 191 192int 193nv04_display_create(struct drm_device *dev) 194{ 195 struct nouveau_drm *drm = nouveau_drm(dev); 196 struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); 197 struct dcb_table *dcb = &drm->vbios.dcb; 198 struct drm_connector *connector, *ct; 199 struct drm_encoder *encoder; 200 struct nouveau_encoder *nv_encoder; 201 struct nouveau_crtc *crtc; 202 struct nv04_display *disp; 203 int i, ret; 204 205 disp = kzalloc(sizeof(*disp), GFP_KERNEL); 206 if (!disp) 207 return -ENOMEM; 208 209 nvif_object_map(&drm->client.device.object, NULL, 0); 210 211 nouveau_display(dev)->priv = disp; 212 nouveau_display(dev)->dtor = nv04_display_destroy; 213 nouveau_display(dev)->init = nv04_display_init; 214 nouveau_display(dev)->fini = nv04_display_fini; 215 216 /* Pre-nv50 doesn't support atomic, so don't expose the ioctls */ 217 dev->driver_features &= ~DRIVER_ATOMIC; 218 219 /* Request page flip completion event. */ 220 if (drm->nvsw.client) { 221 nvif_notify_init(&drm->nvsw, nv04_flip_complete, 222 false, NV04_NVSW_NTFY_UEVENT, 223 NULL, 0, 0, &disp->flip); 224 } 225 226 nouveau_hw_save_vga_fonts(dev, 1); 227 228 nv04_crtc_create(dev, 0); 229 if (nv_two_heads(dev)) 230 nv04_crtc_create(dev, 1); 231 232 for (i = 0; i < dcb->entries; i++) { 233 struct dcb_output *dcbent = &dcb->entry[i]; 234 235 connector = nouveau_connector_create(dev, dcbent); 236 if (IS_ERR(connector)) 237 continue; 238 239 switch (dcbent->type) { 240 case DCB_OUTPUT_ANALOG: 241 ret = nv04_dac_create(connector, dcbent); 242 break; 243 case DCB_OUTPUT_LVDS: 244 case DCB_OUTPUT_TMDS: 245 ret = nv04_dfp_create(connector, dcbent); 246 break; 247 case DCB_OUTPUT_TV: 248 if (dcbent->location == DCB_LOC_ON_CHIP) 249 ret = nv17_tv_create(connector, dcbent); 250 else 251 ret = nv04_tv_create(connector, dcbent); 252 break; 253 default: 254 NV_WARN(drm, "DCB type %d not known\n", dcbent->type); 255 continue; 256 } 257 258 if (ret) 259 continue; 260 } 261 262 list_for_each_entry_safe(connector, ct, 263 &dev->mode_config.connector_list, head) { 264 if (!connector->possible_encoders) { 265 NV_WARN(drm, "%s has no encoders, removing\n", 266 connector->name); 267 connector->funcs->destroy(connector); 268 } 269 } 270 271 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 272 struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); 273 struct nvkm_i2c_bus *bus = 274 nvkm_i2c_bus_find(i2c, nv_encoder->dcb->i2c_index); 275 nv_encoder->i2c = bus ? &bus->i2c : NULL; 276 } 277 278 /* Save previous state */ 279 list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) 280 crtc->save(&crtc->base); 281 282 list_for_each_entry(nv_encoder, &dev->mode_config.encoder_list, base.base.head) 283 nv_encoder->enc_save(&nv_encoder->base.base); 284 285 nouveau_overlay_init(dev); 286 287 return 0; 288} 289