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
nv04_display_fini(struct drm_device * dev,bool suspend)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
nv04_display_init(struct drm_device * dev,bool resume,bool runtime)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
nv04_display_destroy(struct drm_device * dev)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
nv04_display_create(struct drm_device * dev)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