Home | History | Annotate | Line # | Download | only in dispnv04
      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 
     41 static void
     42 nv04_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 
     79 static int
     80 nv04_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 
    167 static void
    168 nv04_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 
    192 int
    193 nv04_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