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