1 | /* |
2 | * Copyright 1993-2003 NVIDIA, Corporation |
3 | * Copyright 2006 Dave Airlie |
4 | * Copyright 2007 Maarten Maathuis |
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 (including the next |
14 | * paragraph) shall be included in all copies or substantial portions of the |
15 | * Software. |
16 | * |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
23 | * DEALINGS IN THE SOFTWARE. |
24 | */ |
25 | #include <drm/drm_crtc_helper.h> |
26 | #include <drm/drm_fourcc.h> |
27 | #include <drm/drm_modeset_helper_vtables.h> |
28 | #include <drm/drm_plane_helper.h> |
29 | #include <drm/drm_vblank.h> |
30 | |
31 | #include "nouveau_drv.h" |
32 | #include "nouveau_reg.h" |
33 | #include "nouveau_ttm.h" |
34 | #include "nouveau_bo.h" |
35 | #include "nouveau_gem.h" |
36 | #include "nouveau_encoder.h" |
37 | #include "nouveau_connector.h" |
38 | #include "nouveau_crtc.h" |
39 | #include "hw.h" |
40 | #include "nvreg.h" |
41 | #include "disp.h" |
42 | #include "nouveau_dma.h" |
43 | |
44 | #include <subdev/bios/pll.h> |
45 | #include <subdev/clk.h> |
46 | |
47 | #include <nvif/push006c.h> |
48 | |
49 | #include <nvif/event.h> |
50 | #include <nvif/cl0046.h> |
51 | |
52 | static int |
53 | nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, |
54 | struct drm_framebuffer *old_fb); |
55 | |
56 | static void |
57 | crtc_wr_cio_state(struct drm_crtc *crtc, struct nv04_crtc_reg *crtcstate, int index) |
58 | { |
59 | NVWriteVgaCrtc(dev: crtc->dev, head: nouveau_crtc(crtc)->index, index, |
60 | value: crtcstate->CRTC[index]); |
61 | } |
62 | |
63 | static void nv_crtc_set_digital_vibrance(struct drm_crtc *crtc, int level) |
64 | { |
65 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
66 | struct drm_device *dev = crtc->dev; |
67 | struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; |
68 | |
69 | regp->CRTC[NV_CIO_CRE_CSB] = nv_crtc->saturation = level; |
70 | if (nv_crtc->saturation && nv_gf4_disp_arch(dev: crtc->dev)) { |
71 | regp->CRTC[NV_CIO_CRE_CSB] = 0x80; |
72 | regp->CRTC[NV_CIO_CRE_5B] = nv_crtc->saturation << 2; |
73 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_5B); |
74 | } |
75 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_CSB); |
76 | } |
77 | |
78 | static void nv_crtc_set_image_sharpening(struct drm_crtc *crtc, int level) |
79 | { |
80 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
81 | struct drm_device *dev = crtc->dev; |
82 | struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; |
83 | |
84 | nv_crtc->sharpness = level; |
85 | if (level < 0) /* blur is in hw range 0x3f -> 0x20 */ |
86 | level += 0x40; |
87 | regp->ramdac_634 = level; |
88 | NVWriteRAMDAC(dev: crtc->dev, head: nv_crtc->index, NV_PRAMDAC_634, val: regp->ramdac_634); |
89 | } |
90 | |
91 | #define PLLSEL_VPLL1_MASK \ |
92 | (NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_VPLL \ |
93 | | NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB2) |
94 | #define PLLSEL_VPLL2_MASK \ |
95 | (NV_PRAMDAC_PLL_COEFF_SELECT_PLL_SOURCE_VPLL2 \ |
96 | | NV_PRAMDAC_PLL_COEFF_SELECT_VCLK2_RATIO_DB2) |
97 | #define PLLSEL_TV_MASK \ |
98 | (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \ |
99 | | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1 \ |
100 | | NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK2 \ |
101 | | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK2) |
102 | |
103 | /* NV4x 0x40.. pll notes: |
104 | * gpu pll: 0x4000 + 0x4004 |
105 | * ?gpu? pll: 0x4008 + 0x400c |
106 | * vpll1: 0x4010 + 0x4014 |
107 | * vpll2: 0x4018 + 0x401c |
108 | * mpll: 0x4020 + 0x4024 |
109 | * mpll: 0x4038 + 0x403c |
110 | * |
111 | * the first register of each pair has some unknown details: |
112 | * bits 0-7: redirected values from elsewhere? (similar to PLL_SETUP_CONTROL?) |
113 | * bits 20-23: (mpll) something to do with post divider? |
114 | * bits 28-31: related to single stage mode? (bit 8/12) |
115 | */ |
116 | |
117 | static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mode * mode, int dot_clock) |
118 | { |
119 | struct drm_device *dev = crtc->dev; |
120 | struct nouveau_drm *drm = nouveau_drm(dev); |
121 | struct nvkm_bios *bios = nvxx_bios(&drm->client.device); |
122 | struct nvkm_clk *clk = nvxx_clk(&drm->client.device); |
123 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
124 | struct nv04_mode_state *state = &nv04_display(dev)->mode_reg; |
125 | struct nv04_crtc_reg *regp = &state->crtc_reg[nv_crtc->index]; |
126 | struct nvkm_pll_vals *pv = ®p->pllvals; |
127 | struct nvbios_pll pll_lim; |
128 | |
129 | if (nvbios_pll_parse(bios, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0, |
130 | &pll_lim)) |
131 | return; |
132 | |
133 | /* NM2 == 0 is used to determine single stage mode on two stage plls */ |
134 | pv->NM2 = 0; |
135 | |
136 | /* for newer nv4x the blob uses only the first stage of the vpll below a |
137 | * certain clock. for a certain nv4b this is 150MHz. since the max |
138 | * output frequency of the first stage for this card is 300MHz, it is |
139 | * assumed the threshold is given by vco1 maxfreq/2 |
140 | */ |
141 | /* for early nv4x, specifically nv40 and *some* nv43 (devids 0 and 6, |
142 | * not 8, others unknown), the blob always uses both plls. no problem |
143 | * has yet been observed in allowing the use a single stage pll on all |
144 | * nv43 however. the behaviour of single stage use is untested on nv40 |
145 | */ |
146 | if (drm->client.device.info.chipset > 0x40 && dot_clock <= (pll_lim.vco1.max_freq / 2)) |
147 | memset(&pll_lim.vco2, 0, sizeof(pll_lim.vco2)); |
148 | |
149 | |
150 | if (!clk->pll_calc(clk, &pll_lim, dot_clock, pv)) |
151 | return; |
152 | |
153 | state->pllsel &= PLLSEL_VPLL1_MASK | PLLSEL_VPLL2_MASK | PLLSEL_TV_MASK; |
154 | |
155 | /* The blob uses this always, so let's do the same */ |
156 | if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) |
157 | state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_USE_VPLL2_TRUE; |
158 | /* again nv40 and some nv43 act more like nv3x as described above */ |
159 | if (drm->client.device.info.chipset < 0x41) |
160 | state->pllsel |= NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_MPLL | |
161 | NV_PRAMDAC_PLL_COEFF_SELECT_SOURCE_PROG_NVPLL; |
162 | state->pllsel |= nv_crtc->index ? PLLSEL_VPLL2_MASK : PLLSEL_VPLL1_MASK; |
163 | |
164 | if (pv->NM2) |
165 | NV_DEBUG(drm, "vpll: n1 %d n2 %d m1 %d m2 %d log2p %d\n" , |
166 | pv->N1, pv->N2, pv->M1, pv->M2, pv->log2P); |
167 | else |
168 | NV_DEBUG(drm, "vpll: n %d m %d log2p %d\n" , |
169 | pv->N1, pv->M1, pv->log2P); |
170 | |
171 | nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset); |
172 | } |
173 | |
174 | static void |
175 | nv_crtc_dpms(struct drm_crtc *crtc, int mode) |
176 | { |
177 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
178 | struct drm_device *dev = crtc->dev; |
179 | struct nouveau_drm *drm = nouveau_drm(dev); |
180 | unsigned char seq1 = 0, crtc17 = 0; |
181 | unsigned char crtc1A; |
182 | |
183 | NV_DEBUG(drm, "Setting dpms mode %d on CRTC %d\n" , mode, |
184 | nv_crtc->index); |
185 | |
186 | if (nv_crtc->last_dpms == mode) /* Don't do unnecessary mode changes. */ |
187 | return; |
188 | |
189 | nv_crtc->last_dpms = mode; |
190 | |
191 | if (nv_two_heads(dev)) |
192 | NVSetOwner(dev, owner: nv_crtc->index); |
193 | |
194 | /* nv4ref indicates these two RPC1 bits inhibit h/v sync */ |
195 | crtc1A = NVReadVgaCrtc(dev, head: nv_crtc->index, |
196 | NV_CIO_CRE_RPC1_INDEX) & ~0xC0; |
197 | switch (mode) { |
198 | case DRM_MODE_DPMS_STANDBY: |
199 | /* Screen: Off; HSync: Off, VSync: On -- Not Supported */ |
200 | seq1 = 0x20; |
201 | crtc17 = 0x80; |
202 | crtc1A |= 0x80; |
203 | break; |
204 | case DRM_MODE_DPMS_SUSPEND: |
205 | /* Screen: Off; HSync: On, VSync: Off -- Not Supported */ |
206 | seq1 = 0x20; |
207 | crtc17 = 0x80; |
208 | crtc1A |= 0x40; |
209 | break; |
210 | case DRM_MODE_DPMS_OFF: |
211 | /* Screen: Off; HSync: Off, VSync: Off */ |
212 | seq1 = 0x20; |
213 | crtc17 = 0x00; |
214 | crtc1A |= 0xC0; |
215 | break; |
216 | case DRM_MODE_DPMS_ON: |
217 | default: |
218 | /* Screen: On; HSync: On, VSync: On */ |
219 | seq1 = 0x00; |
220 | crtc17 = 0x80; |
221 | break; |
222 | } |
223 | |
224 | NVVgaSeqReset(dev, head: nv_crtc->index, start: true); |
225 | /* Each head has it's own sequencer, so we can turn it off when we want */ |
226 | seq1 |= (NVReadVgaSeq(dev, head: nv_crtc->index, NV_VIO_SR_CLOCK_INDEX) & ~0x20); |
227 | NVWriteVgaSeq(dev, head: nv_crtc->index, NV_VIO_SR_CLOCK_INDEX, value: seq1); |
228 | crtc17 |= (NVReadVgaCrtc(dev, head: nv_crtc->index, NV_CIO_CR_MODE_INDEX) & ~0x80); |
229 | mdelay(10); |
230 | NVWriteVgaCrtc(dev, head: nv_crtc->index, NV_CIO_CR_MODE_INDEX, value: crtc17); |
231 | NVVgaSeqReset(dev, head: nv_crtc->index, start: false); |
232 | |
233 | NVWriteVgaCrtc(dev, head: nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, value: crtc1A); |
234 | } |
235 | |
236 | static void |
237 | nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) |
238 | { |
239 | struct drm_device *dev = crtc->dev; |
240 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
241 | struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; |
242 | struct drm_framebuffer *fb = crtc->primary->fb; |
243 | |
244 | /* Calculate our timings */ |
245 | int horizDisplay = (mode->crtc_hdisplay >> 3) - 1; |
246 | int horizStart = (mode->crtc_hsync_start >> 3) + 1; |
247 | int horizEnd = (mode->crtc_hsync_end >> 3) + 1; |
248 | int horizTotal = (mode->crtc_htotal >> 3) - 5; |
249 | int horizBlankStart = (mode->crtc_hdisplay >> 3) - 1; |
250 | int horizBlankEnd = (mode->crtc_htotal >> 3) - 1; |
251 | int vertDisplay = mode->crtc_vdisplay - 1; |
252 | int vertStart = mode->crtc_vsync_start - 1; |
253 | int vertEnd = mode->crtc_vsync_end - 1; |
254 | int vertTotal = mode->crtc_vtotal - 2; |
255 | int vertBlankStart = mode->crtc_vdisplay - 1; |
256 | int vertBlankEnd = mode->crtc_vtotal - 1; |
257 | |
258 | struct drm_encoder *encoder; |
259 | bool fp_output = false; |
260 | |
261 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
262 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
263 | |
264 | if (encoder->crtc == crtc && |
265 | (nv_encoder->dcb->type == DCB_OUTPUT_LVDS || |
266 | nv_encoder->dcb->type == DCB_OUTPUT_TMDS)) |
267 | fp_output = true; |
268 | } |
269 | |
270 | if (fp_output) { |
271 | vertStart = vertTotal - 3; |
272 | vertEnd = vertTotal - 2; |
273 | vertBlankStart = vertStart; |
274 | horizStart = horizTotal - 5; |
275 | horizEnd = horizTotal - 2; |
276 | horizBlankEnd = horizTotal + 4; |
277 | #if 0 |
278 | if (dev->overlayAdaptor && drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) |
279 | /* This reportedly works around some video overlay bandwidth problems */ |
280 | horizTotal += 2; |
281 | #endif |
282 | } |
283 | |
284 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
285 | vertTotal |= 1; |
286 | |
287 | #if 0 |
288 | ErrorF("horizDisplay: 0x%X \n" , horizDisplay); |
289 | ErrorF("horizStart: 0x%X \n" , horizStart); |
290 | ErrorF("horizEnd: 0x%X \n" , horizEnd); |
291 | ErrorF("horizTotal: 0x%X \n" , horizTotal); |
292 | ErrorF("horizBlankStart: 0x%X \n" , horizBlankStart); |
293 | ErrorF("horizBlankEnd: 0x%X \n" , horizBlankEnd); |
294 | ErrorF("vertDisplay: 0x%X \n" , vertDisplay); |
295 | ErrorF("vertStart: 0x%X \n" , vertStart); |
296 | ErrorF("vertEnd: 0x%X \n" , vertEnd); |
297 | ErrorF("vertTotal: 0x%X \n" , vertTotal); |
298 | ErrorF("vertBlankStart: 0x%X \n" , vertBlankStart); |
299 | ErrorF("vertBlankEnd: 0x%X \n" , vertBlankEnd); |
300 | #endif |
301 | |
302 | /* |
303 | * compute correct Hsync & Vsync polarity |
304 | */ |
305 | if ((mode->flags & (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC)) |
306 | && (mode->flags & (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))) { |
307 | |
308 | regp->MiscOutReg = 0x23; |
309 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
310 | regp->MiscOutReg |= 0x40; |
311 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
312 | regp->MiscOutReg |= 0x80; |
313 | } else { |
314 | int vdisplay = mode->vdisplay; |
315 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
316 | vdisplay *= 2; |
317 | if (mode->vscan > 1) |
318 | vdisplay *= mode->vscan; |
319 | if (vdisplay < 400) |
320 | regp->MiscOutReg = 0xA3; /* +hsync -vsync */ |
321 | else if (vdisplay < 480) |
322 | regp->MiscOutReg = 0x63; /* -hsync +vsync */ |
323 | else if (vdisplay < 768) |
324 | regp->MiscOutReg = 0xE3; /* -hsync -vsync */ |
325 | else |
326 | regp->MiscOutReg = 0x23; /* +hsync +vsync */ |
327 | } |
328 | |
329 | /* |
330 | * Time Sequencer |
331 | */ |
332 | regp->Sequencer[NV_VIO_SR_RESET_INDEX] = 0x00; |
333 | /* 0x20 disables the sequencer */ |
334 | if (mode->flags & DRM_MODE_FLAG_CLKDIV2) |
335 | regp->Sequencer[NV_VIO_SR_CLOCK_INDEX] = 0x29; |
336 | else |
337 | regp->Sequencer[NV_VIO_SR_CLOCK_INDEX] = 0x21; |
338 | regp->Sequencer[NV_VIO_SR_PLANE_MASK_INDEX] = 0x0F; |
339 | regp->Sequencer[NV_VIO_SR_CHAR_MAP_INDEX] = 0x00; |
340 | regp->Sequencer[NV_VIO_SR_MEM_MODE_INDEX] = 0x0E; |
341 | |
342 | /* |
343 | * CRTC |
344 | */ |
345 | regp->CRTC[NV_CIO_CR_HDT_INDEX] = horizTotal; |
346 | regp->CRTC[NV_CIO_CR_HDE_INDEX] = horizDisplay; |
347 | regp->CRTC[NV_CIO_CR_HBS_INDEX] = horizBlankStart; |
348 | regp->CRTC[NV_CIO_CR_HBE_INDEX] = (1 << 7) | |
349 | XLATE(horizBlankEnd, 0, NV_CIO_CR_HBE_4_0); |
350 | regp->CRTC[NV_CIO_CR_HRS_INDEX] = horizStart; |
351 | regp->CRTC[NV_CIO_CR_HRE_INDEX] = XLATE(horizBlankEnd, 5, NV_CIO_CR_HRE_HBE_5) | |
352 | XLATE(horizEnd, 0, NV_CIO_CR_HRE_4_0); |
353 | regp->CRTC[NV_CIO_CR_VDT_INDEX] = vertTotal; |
354 | regp->CRTC[NV_CIO_CR_OVL_INDEX] = XLATE(vertStart, 9, NV_CIO_CR_OVL_VRS_9) | |
355 | XLATE(vertDisplay, 9, NV_CIO_CR_OVL_VDE_9) | |
356 | XLATE(vertTotal, 9, NV_CIO_CR_OVL_VDT_9) | |
357 | (1 << 4) | |
358 | XLATE(vertBlankStart, 8, NV_CIO_CR_OVL_VBS_8) | |
359 | XLATE(vertStart, 8, NV_CIO_CR_OVL_VRS_8) | |
360 | XLATE(vertDisplay, 8, NV_CIO_CR_OVL_VDE_8) | |
361 | XLATE(vertTotal, 8, NV_CIO_CR_OVL_VDT_8); |
362 | regp->CRTC[NV_CIO_CR_RSAL_INDEX] = 0x00; |
363 | regp->CRTC[NV_CIO_CR_CELL_HT_INDEX] = ((mode->flags & DRM_MODE_FLAG_DBLSCAN) ? MASK(NV_CIO_CR_CELL_HT_SCANDBL) : 0) | |
364 | 1 << 6 | |
365 | XLATE(vertBlankStart, 9, NV_CIO_CR_CELL_HT_VBS_9); |
366 | regp->CRTC[NV_CIO_CR_CURS_ST_INDEX] = 0x00; |
367 | regp->CRTC[NV_CIO_CR_CURS_END_INDEX] = 0x00; |
368 | regp->CRTC[NV_CIO_CR_SA_HI_INDEX] = 0x00; |
369 | regp->CRTC[NV_CIO_CR_SA_LO_INDEX] = 0x00; |
370 | regp->CRTC[NV_CIO_CR_TCOFF_HI_INDEX] = 0x00; |
371 | regp->CRTC[NV_CIO_CR_TCOFF_LO_INDEX] = 0x00; |
372 | regp->CRTC[NV_CIO_CR_VRS_INDEX] = vertStart; |
373 | regp->CRTC[NV_CIO_CR_VRE_INDEX] = 1 << 5 | XLATE(vertEnd, 0, NV_CIO_CR_VRE_3_0); |
374 | regp->CRTC[NV_CIO_CR_VDE_INDEX] = vertDisplay; |
375 | /* framebuffer can be larger than crtc scanout area. */ |
376 | regp->CRTC[NV_CIO_CR_OFFSET_INDEX] = fb->pitches[0] / 8; |
377 | regp->CRTC[NV_CIO_CR_ULINE_INDEX] = 0x00; |
378 | regp->CRTC[NV_CIO_CR_VBS_INDEX] = vertBlankStart; |
379 | regp->CRTC[NV_CIO_CR_VBE_INDEX] = vertBlankEnd; |
380 | regp->CRTC[NV_CIO_CR_MODE_INDEX] = 0x43; |
381 | regp->CRTC[NV_CIO_CR_LCOMP_INDEX] = 0xff; |
382 | |
383 | /* |
384 | * Some extended CRTC registers (they are not saved with the rest of the vga regs). |
385 | */ |
386 | |
387 | /* framebuffer can be larger than crtc scanout area. */ |
388 | regp->CRTC[NV_CIO_CRE_RPC0_INDEX] = |
389 | XLATE(fb->pitches[0] / 8, 8, NV_CIO_CRE_RPC0_OFFSET_10_8); |
390 | regp->CRTC[NV_CIO_CRE_42] = |
391 | XLATE(fb->pitches[0] / 8, 11, NV_CIO_CRE_42_OFFSET_11); |
392 | regp->CRTC[NV_CIO_CRE_RPC1_INDEX] = mode->crtc_hdisplay < 1280 ? |
393 | MASK(NV_CIO_CRE_RPC1_LARGE) : 0x00; |
394 | regp->CRTC[NV_CIO_CRE_LSR_INDEX] = XLATE(horizBlankEnd, 6, NV_CIO_CRE_LSR_HBE_6) | |
395 | XLATE(vertBlankStart, 10, NV_CIO_CRE_LSR_VBS_10) | |
396 | XLATE(vertStart, 10, NV_CIO_CRE_LSR_VRS_10) | |
397 | XLATE(vertDisplay, 10, NV_CIO_CRE_LSR_VDE_10) | |
398 | XLATE(vertTotal, 10, NV_CIO_CRE_LSR_VDT_10); |
399 | regp->CRTC[NV_CIO_CRE_HEB__INDEX] = XLATE(horizStart, 8, NV_CIO_CRE_HEB_HRS_8) | |
400 | XLATE(horizBlankStart, 8, NV_CIO_CRE_HEB_HBS_8) | |
401 | XLATE(horizDisplay, 8, NV_CIO_CRE_HEB_HDE_8) | |
402 | XLATE(horizTotal, 8, NV_CIO_CRE_HEB_HDT_8); |
403 | regp->CRTC[NV_CIO_CRE_EBR_INDEX] = XLATE(vertBlankStart, 11, NV_CIO_CRE_EBR_VBS_11) | |
404 | XLATE(vertStart, 11, NV_CIO_CRE_EBR_VRS_11) | |
405 | XLATE(vertDisplay, 11, NV_CIO_CRE_EBR_VDE_11) | |
406 | XLATE(vertTotal, 11, NV_CIO_CRE_EBR_VDT_11); |
407 | |
408 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) { |
409 | horizTotal = (horizTotal >> 1) & ~1; |
410 | regp->CRTC[NV_CIO_CRE_ILACE__INDEX] = horizTotal; |
411 | regp->CRTC[NV_CIO_CRE_HEB__INDEX] |= XLATE(horizTotal, 8, NV_CIO_CRE_HEB_ILC_8); |
412 | } else |
413 | regp->CRTC[NV_CIO_CRE_ILACE__INDEX] = 0xff; /* interlace off */ |
414 | |
415 | /* |
416 | * Graphics Display Controller |
417 | */ |
418 | regp->Graphics[NV_VIO_GX_SR_INDEX] = 0x00; |
419 | regp->Graphics[NV_VIO_GX_SREN_INDEX] = 0x00; |
420 | regp->Graphics[NV_VIO_GX_CCOMP_INDEX] = 0x00; |
421 | regp->Graphics[NV_VIO_GX_ROP_INDEX] = 0x00; |
422 | regp->Graphics[NV_VIO_GX_READ_MAP_INDEX] = 0x00; |
423 | regp->Graphics[NV_VIO_GX_MODE_INDEX] = 0x40; /* 256 color mode */ |
424 | regp->Graphics[NV_VIO_GX_MISC_INDEX] = 0x05; /* map 64k mem + graphic mode */ |
425 | regp->Graphics[NV_VIO_GX_DONT_CARE_INDEX] = 0x0F; |
426 | regp->Graphics[NV_VIO_GX_BIT_MASK_INDEX] = 0xFF; |
427 | |
428 | regp->Attribute[0] = 0x00; /* standard colormap translation */ |
429 | regp->Attribute[1] = 0x01; |
430 | regp->Attribute[2] = 0x02; |
431 | regp->Attribute[3] = 0x03; |
432 | regp->Attribute[4] = 0x04; |
433 | regp->Attribute[5] = 0x05; |
434 | regp->Attribute[6] = 0x06; |
435 | regp->Attribute[7] = 0x07; |
436 | regp->Attribute[8] = 0x08; |
437 | regp->Attribute[9] = 0x09; |
438 | regp->Attribute[10] = 0x0A; |
439 | regp->Attribute[11] = 0x0B; |
440 | regp->Attribute[12] = 0x0C; |
441 | regp->Attribute[13] = 0x0D; |
442 | regp->Attribute[14] = 0x0E; |
443 | regp->Attribute[15] = 0x0F; |
444 | regp->Attribute[NV_CIO_AR_MODE_INDEX] = 0x01; /* Enable graphic mode */ |
445 | /* Non-vga */ |
446 | regp->Attribute[NV_CIO_AR_OSCAN_INDEX] = 0x00; |
447 | regp->Attribute[NV_CIO_AR_PLANE_INDEX] = 0x0F; /* enable all color planes */ |
448 | regp->Attribute[NV_CIO_AR_HPP_INDEX] = 0x00; |
449 | regp->Attribute[NV_CIO_AR_CSEL_INDEX] = 0x00; |
450 | } |
451 | |
452 | /* |
453 | * Sets up registers for the given mode/adjusted_mode pair. |
454 | * |
455 | * The clocks, CRTCs and outputs attached to this CRTC must be off. |
456 | * |
457 | * This shouldn't enable any clocks, CRTCs, or outputs, but they should |
458 | * be easily turned on/off after this. |
459 | */ |
460 | static void |
461 | nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) |
462 | { |
463 | struct drm_device *dev = crtc->dev; |
464 | struct nouveau_drm *drm = nouveau_drm(dev); |
465 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
466 | struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; |
467 | struct nv04_crtc_reg *savep = &nv04_display(dev)->saved_reg.crtc_reg[nv_crtc->index]; |
468 | const struct drm_framebuffer *fb = crtc->primary->fb; |
469 | struct drm_encoder *encoder; |
470 | bool lvds_output = false, tmds_output = false, tv_output = false, |
471 | off_chip_digital = false; |
472 | |
473 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { |
474 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
475 | bool digital = false; |
476 | |
477 | if (encoder->crtc != crtc) |
478 | continue; |
479 | |
480 | if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS) |
481 | digital = lvds_output = true; |
482 | if (nv_encoder->dcb->type == DCB_OUTPUT_TV) |
483 | tv_output = true; |
484 | if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS) |
485 | digital = tmds_output = true; |
486 | if (nv_encoder->dcb->location != DCB_LOC_ON_CHIP && digital) |
487 | off_chip_digital = true; |
488 | } |
489 | |
490 | /* Registers not directly related to the (s)vga mode */ |
491 | |
492 | /* What is the meaning of this register? */ |
493 | /* A few popular values are 0x18, 0x1c, 0x38, 0x3c */ |
494 | regp->CRTC[NV_CIO_CRE_ENH_INDEX] = savep->CRTC[NV_CIO_CRE_ENH_INDEX] & ~(1<<5); |
495 | |
496 | regp->crtc_eng_ctrl = 0; |
497 | /* Except for rare conditions I2C is enabled on the primary crtc */ |
498 | if (nv_crtc->index == 0) |
499 | regp->crtc_eng_ctrl |= NV_CRTC_FSEL_I2C; |
500 | #if 0 |
501 | /* Set overlay to desired crtc. */ |
502 | if (dev->overlayAdaptor) { |
503 | NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(dev); |
504 | if (pPriv->overlayCRTC == nv_crtc->index) |
505 | regp->crtc_eng_ctrl |= NV_CRTC_FSEL_OVERLAY; |
506 | } |
507 | #endif |
508 | |
509 | /* ADDRESS_SPACE_PNVM is the same as setting HCUR_ASI */ |
510 | regp->cursor_cfg = NV_PCRTC_CURSOR_CONFIG_CUR_LINES_64 | |
511 | NV_PCRTC_CURSOR_CONFIG_CUR_PIXELS_64 | |
512 | NV_PCRTC_CURSOR_CONFIG_ADDRESS_SPACE_PNVM; |
513 | if (drm->client.device.info.chipset >= 0x11) |
514 | regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_CUR_BPP_32; |
515 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
516 | regp->cursor_cfg |= NV_PCRTC_CURSOR_CONFIG_DOUBLE_SCAN_ENABLE; |
517 | |
518 | /* Unblock some timings */ |
519 | regp->CRTC[NV_CIO_CRE_53] = 0; |
520 | regp->CRTC[NV_CIO_CRE_54] = 0; |
521 | |
522 | /* 0x00 is disabled, 0x11 is lvds, 0x22 crt and 0x88 tmds */ |
523 | if (lvds_output) |
524 | regp->CRTC[NV_CIO_CRE_SCRATCH3__INDEX] = 0x11; |
525 | else if (tmds_output) |
526 | regp->CRTC[NV_CIO_CRE_SCRATCH3__INDEX] = 0x88; |
527 | else |
528 | regp->CRTC[NV_CIO_CRE_SCRATCH3__INDEX] = 0x22; |
529 | |
530 | /* These values seem to vary */ |
531 | /* This register seems to be used by the bios to make certain decisions on some G70 cards? */ |
532 | regp->CRTC[NV_CIO_CRE_SCRATCH4__INDEX] = savep->CRTC[NV_CIO_CRE_SCRATCH4__INDEX]; |
533 | |
534 | nv_crtc_set_digital_vibrance(crtc, level: nv_crtc->saturation); |
535 | |
536 | /* probably a scratch reg, but kept for cargo-cult purposes: |
537 | * bit0: crtc0?, head A |
538 | * bit6: lvds, head A |
539 | * bit7: (only in X), head A |
540 | */ |
541 | if (nv_crtc->index == 0) |
542 | regp->CRTC[NV_CIO_CRE_4B] = savep->CRTC[NV_CIO_CRE_4B] | 0x80; |
543 | |
544 | /* The blob seems to take the current value from crtc 0, add 4 to that |
545 | * and reuse the old value for crtc 1 */ |
546 | regp->CRTC[NV_CIO_CRE_TVOUT_LATENCY] = nv04_display(dev)->saved_reg.crtc_reg[0].CRTC[NV_CIO_CRE_TVOUT_LATENCY]; |
547 | if (!nv_crtc->index) |
548 | regp->CRTC[NV_CIO_CRE_TVOUT_LATENCY] += 4; |
549 | |
550 | /* the blob sometimes sets |= 0x10 (which is the same as setting |= |
551 | * 1 << 30 on 0x60.830), for no apparent reason */ |
552 | regp->CRTC[NV_CIO_CRE_59] = off_chip_digital; |
553 | |
554 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_RANKINE) |
555 | regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1; |
556 | |
557 | regp->crtc_830 = mode->crtc_vdisplay - 3; |
558 | regp->crtc_834 = mode->crtc_vdisplay - 1; |
559 | |
560 | if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) |
561 | /* This is what the blob does */ |
562 | regp->crtc_850 = NVReadCRTC(dev, head: 0, NV_PCRTC_850); |
563 | |
564 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_RANKINE) |
565 | regp->gpio_ext = NVReadCRTC(dev, head: 0, NV_PCRTC_GPIO_EXT); |
566 | |
567 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) |
568 | regp->crtc_cfg = NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC; |
569 | else |
570 | regp->crtc_cfg = NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC; |
571 | |
572 | /* Some misc regs */ |
573 | if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) { |
574 | regp->CRTC[NV_CIO_CRE_85] = 0xFF; |
575 | regp->CRTC[NV_CIO_CRE_86] = 0x1; |
576 | } |
577 | |
578 | regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (fb->format->depth + 1) / 8; |
579 | /* Enable slaved mode (called MODE_TV in nv4ref.h) */ |
580 | if (lvds_output || tmds_output || tv_output) |
581 | regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7); |
582 | |
583 | /* Generic PRAMDAC regs */ |
584 | |
585 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) |
586 | /* Only bit that bios and blob set. */ |
587 | regp->nv10_cursync = (1 << 25); |
588 | |
589 | regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS | |
590 | NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL | |
591 | NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON; |
592 | if (fb->format->depth == 16) |
593 | regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; |
594 | if (drm->client.device.info.chipset >= 0x11) |
595 | regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG; |
596 | |
597 | regp->ramdac_630 = 0; /* turn off green mode (tv test pattern?) */ |
598 | regp->tv_setup = 0; |
599 | |
600 | nv_crtc_set_image_sharpening(crtc, level: nv_crtc->sharpness); |
601 | |
602 | /* Some values the blob sets */ |
603 | regp->ramdac_8c0 = 0x100; |
604 | regp->ramdac_a20 = 0x0; |
605 | regp->ramdac_a24 = 0xfffff; |
606 | regp->ramdac_a34 = 0x1; |
607 | } |
608 | |
609 | static int |
610 | nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) |
611 | { |
612 | struct nv04_display *disp = nv04_display(dev: crtc->dev); |
613 | struct drm_framebuffer *fb = crtc->primary->fb; |
614 | struct nouveau_bo *nvbo = nouveau_gem_object(fb->obj[0]); |
615 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
616 | int ret; |
617 | |
618 | ret = nouveau_bo_pin(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, false); |
619 | if (ret == 0) { |
620 | if (disp->image[nv_crtc->index]) |
621 | nouveau_bo_unpin(disp->image[nv_crtc->index]); |
622 | nouveau_bo_ref(nvbo, &disp->image[nv_crtc->index]); |
623 | } |
624 | |
625 | return ret; |
626 | } |
627 | |
628 | /* |
629 | * Sets up registers for the given mode/adjusted_mode pair. |
630 | * |
631 | * The clocks, CRTCs and outputs attached to this CRTC must be off. |
632 | * |
633 | * This shouldn't enable any clocks, CRTCs, or outputs, but they should |
634 | * be easily turned on/off after this. |
635 | */ |
636 | static int |
637 | nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, |
638 | struct drm_display_mode *adjusted_mode, |
639 | int x, int y, struct drm_framebuffer *old_fb) |
640 | { |
641 | struct drm_device *dev = crtc->dev; |
642 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
643 | struct nouveau_drm *drm = nouveau_drm(dev); |
644 | int ret; |
645 | |
646 | NV_DEBUG(drm, "CTRC mode on CRTC %d:\n" , nv_crtc->index); |
647 | drm_mode_debug_printmodeline(mode: adjusted_mode); |
648 | |
649 | ret = nv_crtc_swap_fbs(crtc, old_fb); |
650 | if (ret) |
651 | return ret; |
652 | |
653 | /* unlock must come after turning off FP_TG_CONTROL in output_prepare */ |
654 | nv_lock_vga_crtc_shadow(dev, head: nv_crtc->index, lock: -1); |
655 | |
656 | nv_crtc_mode_set_vga(crtc, mode: adjusted_mode); |
657 | /* calculated in nv04_dfp_prepare, nv40 needs it written before calculating PLLs */ |
658 | if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) |
659 | NVWriteRAMDAC(dev, head: 0, NV_PRAMDAC_SEL_CLK, val: nv04_display(dev)->mode_reg.sel_clk); |
660 | nv_crtc_mode_set_regs(crtc, mode: adjusted_mode); |
661 | nv_crtc_calc_state_ext(crtc, mode, dot_clock: adjusted_mode->clock); |
662 | return 0; |
663 | } |
664 | |
665 | static void nv_crtc_save(struct drm_crtc *crtc) |
666 | { |
667 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
668 | struct drm_device *dev = crtc->dev; |
669 | struct nv04_mode_state *state = &nv04_display(dev)->mode_reg; |
670 | struct nv04_crtc_reg *crtc_state = &state->crtc_reg[nv_crtc->index]; |
671 | struct nv04_mode_state *saved = &nv04_display(dev)->saved_reg; |
672 | struct nv04_crtc_reg *crtc_saved = &saved->crtc_reg[nv_crtc->index]; |
673 | |
674 | if (nv_two_heads(dev: crtc->dev)) |
675 | NVSetOwner(crtc->dev, owner: nv_crtc->index); |
676 | |
677 | nouveau_hw_save_state(crtc->dev, head: nv_crtc->index, state: saved); |
678 | |
679 | /* init some state to saved value */ |
680 | state->sel_clk = saved->sel_clk & ~(0x5 << 16); |
681 | crtc_state->CRTC[NV_CIO_CRE_LCD__INDEX] = crtc_saved->CRTC[NV_CIO_CRE_LCD__INDEX]; |
682 | state->pllsel = saved->pllsel & ~(PLLSEL_VPLL1_MASK | PLLSEL_VPLL2_MASK | PLLSEL_TV_MASK); |
683 | crtc_state->gpio_ext = crtc_saved->gpio_ext; |
684 | } |
685 | |
686 | static void nv_crtc_restore(struct drm_crtc *crtc) |
687 | { |
688 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
689 | struct drm_device *dev = crtc->dev; |
690 | int head = nv_crtc->index; |
691 | uint8_t saved_cr21 = nv04_display(dev)->saved_reg.crtc_reg[head].CRTC[NV_CIO_CRE_21]; |
692 | |
693 | if (nv_two_heads(dev: crtc->dev)) |
694 | NVSetOwner(crtc->dev, owner: head); |
695 | |
696 | nouveau_hw_load_state(crtc->dev, head, state: &nv04_display(dev)->saved_reg); |
697 | nv_lock_vga_crtc_shadow(dev: crtc->dev, head, lock: saved_cr21); |
698 | |
699 | nv_crtc->last_dpms = NV_DPMS_CLEARED; |
700 | } |
701 | |
702 | static void nv_crtc_prepare(struct drm_crtc *crtc) |
703 | { |
704 | struct drm_device *dev = crtc->dev; |
705 | struct nouveau_drm *drm = nouveau_drm(dev); |
706 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
707 | const struct drm_crtc_helper_funcs *funcs = crtc->helper_private; |
708 | |
709 | if (nv_two_heads(dev)) |
710 | NVSetOwner(dev, owner: nv_crtc->index); |
711 | |
712 | drm_crtc_vblank_off(crtc); |
713 | funcs->dpms(crtc, DRM_MODE_DPMS_OFF); |
714 | |
715 | NVBlankScreen(dev, head: nv_crtc->index, blank: true); |
716 | |
717 | /* Some more preparation. */ |
718 | NVWriteCRTC(dev, head: nv_crtc->index, NV_PCRTC_CONFIG, NV_PCRTC_CONFIG_START_ADDRESS_NON_VGA); |
719 | if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE) { |
720 | uint32_t reg900 = NVReadRAMDAC(dev, head: nv_crtc->index, NV_PRAMDAC_900); |
721 | NVWriteRAMDAC(dev, head: nv_crtc->index, NV_PRAMDAC_900, val: reg900 & ~0x10000); |
722 | } |
723 | } |
724 | |
725 | static void nv_crtc_commit(struct drm_crtc *crtc) |
726 | { |
727 | struct drm_device *dev = crtc->dev; |
728 | const struct drm_crtc_helper_funcs *funcs = crtc->helper_private; |
729 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
730 | |
731 | nouveau_hw_load_state(dev, head: nv_crtc->index, state: &nv04_display(dev)->mode_reg); |
732 | nv04_crtc_mode_set_base(crtc, x: crtc->x, y: crtc->y, NULL); |
733 | |
734 | #ifdef __BIG_ENDIAN |
735 | /* turn on LFB swapping */ |
736 | { |
737 | uint8_t tmp = NVReadVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RCR); |
738 | tmp |= MASK(NV_CIO_CRE_RCR_ENDIAN_BIG); |
739 | NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RCR, tmp); |
740 | } |
741 | #endif |
742 | |
743 | funcs->dpms(crtc, DRM_MODE_DPMS_ON); |
744 | drm_crtc_vblank_on(crtc); |
745 | } |
746 | |
747 | static void nv_crtc_destroy(struct drm_crtc *crtc) |
748 | { |
749 | struct nv04_display *disp = nv04_display(dev: crtc->dev); |
750 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
751 | |
752 | if (!nv_crtc) |
753 | return; |
754 | |
755 | drm_crtc_cleanup(crtc); |
756 | |
757 | if (disp->image[nv_crtc->index]) |
758 | nouveau_bo_unpin(disp->image[nv_crtc->index]); |
759 | nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]); |
760 | |
761 | nouveau_bo_unmap(nv_crtc->cursor.nvbo); |
762 | nouveau_bo_unpin(nv_crtc->cursor.nvbo); |
763 | nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); |
764 | nvif_event_dtor(&nv_crtc->vblank); |
765 | nvif_head_dtor(&nv_crtc->head); |
766 | kfree(objp: nv_crtc); |
767 | } |
768 | |
769 | static void |
770 | nv_crtc_gamma_load(struct drm_crtc *crtc) |
771 | { |
772 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
773 | struct drm_device *dev = nv_crtc->base.dev; |
774 | struct rgb { uint8_t r, g, b; } __attribute__((packed)) *rgbs; |
775 | u16 *r, *g, *b; |
776 | int i; |
777 | |
778 | rgbs = (struct rgb *)nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index].DAC; |
779 | r = crtc->gamma_store; |
780 | g = r + crtc->gamma_size; |
781 | b = g + crtc->gamma_size; |
782 | |
783 | for (i = 0; i < 256; i++) { |
784 | rgbs[i].r = *r++ >> 8; |
785 | rgbs[i].g = *g++ >> 8; |
786 | rgbs[i].b = *b++ >> 8; |
787 | } |
788 | |
789 | nouveau_hw_load_state_palette(dev, head: nv_crtc->index, state: &nv04_display(dev)->mode_reg); |
790 | } |
791 | |
792 | static void |
793 | nv_crtc_disable(struct drm_crtc *crtc) |
794 | { |
795 | struct nv04_display *disp = nv04_display(dev: crtc->dev); |
796 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
797 | if (disp->image[nv_crtc->index]) |
798 | nouveau_bo_unpin(disp->image[nv_crtc->index]); |
799 | nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]); |
800 | } |
801 | |
802 | static int |
803 | nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, |
804 | uint32_t size, |
805 | struct drm_modeset_acquire_ctx *ctx) |
806 | { |
807 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
808 | |
809 | /* We need to know the depth before we upload, but it's possible to |
810 | * get called before a framebuffer is bound. If this is the case, |
811 | * mark the lut values as dirty by setting depth==0, and it'll be |
812 | * uploaded on the first mode_set_base() |
813 | */ |
814 | if (!nv_crtc->base.primary->fb) { |
815 | nv_crtc->lut.depth = 0; |
816 | return 0; |
817 | } |
818 | |
819 | nv_crtc_gamma_load(crtc); |
820 | |
821 | return 0; |
822 | } |
823 | |
824 | static int |
825 | nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, |
826 | struct drm_framebuffer *passed_fb, |
827 | int x, int y, bool atomic) |
828 | { |
829 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
830 | struct drm_device *dev = crtc->dev; |
831 | struct nouveau_drm *drm = nouveau_drm(dev); |
832 | struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; |
833 | struct nouveau_bo *nvbo; |
834 | struct drm_framebuffer *drm_fb; |
835 | int arb_burst, arb_lwm; |
836 | |
837 | NV_DEBUG(drm, "index %d\n" , nv_crtc->index); |
838 | |
839 | /* no fb bound */ |
840 | if (!atomic && !crtc->primary->fb) { |
841 | NV_DEBUG(drm, "No FB bound\n" ); |
842 | return 0; |
843 | } |
844 | |
845 | /* If atomic, we want to switch to the fb we were passed, so |
846 | * now we update pointers to do that. |
847 | */ |
848 | if (atomic) { |
849 | drm_fb = passed_fb; |
850 | } else { |
851 | drm_fb = crtc->primary->fb; |
852 | } |
853 | |
854 | nvbo = nouveau_gem_object(drm_fb->obj[0]); |
855 | nv_crtc->fb.offset = nvbo->offset; |
856 | |
857 | if (nv_crtc->lut.depth != drm_fb->format->depth) { |
858 | nv_crtc->lut.depth = drm_fb->format->depth; |
859 | nv_crtc_gamma_load(crtc); |
860 | } |
861 | |
862 | /* Update the framebuffer format. */ |
863 | regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3; |
864 | regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (drm_fb->format->depth + 1) / 8; |
865 | regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; |
866 | if (drm_fb->format->depth == 16) |
867 | regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; |
868 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_PIXEL_INDEX); |
869 | NVWriteRAMDAC(dev, head: nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL, |
870 | val: regp->ramdac_gen_ctrl); |
871 | |
872 | regp->CRTC[NV_CIO_CR_OFFSET_INDEX] = drm_fb->pitches[0] >> 3; |
873 | regp->CRTC[NV_CIO_CRE_RPC0_INDEX] = |
874 | XLATE(drm_fb->pitches[0] >> 3, 8, NV_CIO_CRE_RPC0_OFFSET_10_8); |
875 | regp->CRTC[NV_CIO_CRE_42] = |
876 | XLATE(drm_fb->pitches[0] / 8, 11, NV_CIO_CRE_42_OFFSET_11); |
877 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_RPC0_INDEX); |
878 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CR_OFFSET_INDEX); |
879 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_42); |
880 | |
881 | /* Update the framebuffer location. */ |
882 | regp->fb_start = nv_crtc->fb.offset & ~3; |
883 | regp->fb_start += (y * drm_fb->pitches[0]) + (x * drm_fb->format->cpp[0]); |
884 | nv_set_crtc_base(dev, head: nv_crtc->index, offset: regp->fb_start); |
885 | |
886 | /* Update the arbitration parameters. */ |
887 | nouveau_calc_arb(dev, vclk: crtc->mode.clock, bpp: drm_fb->format->cpp[0] * 8, |
888 | burst: &arb_burst, lwm: &arb_lwm); |
889 | |
890 | regp->CRTC[NV_CIO_CRE_FF_INDEX] = arb_burst; |
891 | regp->CRTC[NV_CIO_CRE_FFLWM__INDEX] = arb_lwm & 0xff; |
892 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_FF_INDEX); |
893 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_FFLWM__INDEX); |
894 | |
895 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_KELVIN) { |
896 | regp->CRTC[NV_CIO_CRE_47] = arb_lwm >> 8; |
897 | crtc_wr_cio_state(crtc, crtcstate: regp, NV_CIO_CRE_47); |
898 | } |
899 | |
900 | return 0; |
901 | } |
902 | |
903 | static int |
904 | nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, |
905 | struct drm_framebuffer *old_fb) |
906 | { |
907 | int ret = nv_crtc_swap_fbs(crtc, old_fb); |
908 | if (ret) |
909 | return ret; |
910 | return nv04_crtc_do_mode_set_base(crtc, passed_fb: old_fb, x, y, atomic: false); |
911 | } |
912 | |
913 | static int |
914 | nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc, |
915 | struct drm_framebuffer *fb, |
916 | int x, int y, enum mode_set_atomic state) |
917 | { |
918 | return nv04_crtc_do_mode_set_base(crtc, passed_fb: fb, x, y, atomic: true); |
919 | } |
920 | |
921 | static void nv04_cursor_upload(struct drm_device *dev, struct nouveau_bo *src, |
922 | struct nouveau_bo *dst) |
923 | { |
924 | int width = nv_cursor_width(dev); |
925 | uint32_t pixel; |
926 | int i, j; |
927 | |
928 | for (i = 0; i < width; i++) { |
929 | for (j = 0; j < width; j++) { |
930 | pixel = nouveau_bo_rd32(src, i*64 + j); |
931 | |
932 | nouveau_bo_wr16(dst, i*width + j, (pixel & 0x80000000) >> 16 |
933 | | (pixel & 0xf80000) >> 9 |
934 | | (pixel & 0xf800) >> 6 |
935 | | (pixel & 0xf8) >> 3); |
936 | } |
937 | } |
938 | } |
939 | |
940 | static void nv11_cursor_upload(struct drm_device *dev, struct nouveau_bo *src, |
941 | struct nouveau_bo *dst) |
942 | { |
943 | uint32_t pixel; |
944 | int alpha, i; |
945 | |
946 | /* nv11+ supports premultiplied (PM), or non-premultiplied (NPM) alpha |
947 | * cursors (though NPM in combination with fp dithering may not work on |
948 | * nv11, from "nv" driver history) |
949 | * NPM mode needs NV_PCRTC_CURSOR_CONFIG_ALPHA_BLEND set and is what the |
950 | * blob uses, however we get given PM cursors so we use PM mode |
951 | */ |
952 | for (i = 0; i < 64 * 64; i++) { |
953 | pixel = nouveau_bo_rd32(src, i); |
954 | |
955 | /* hw gets unhappy if alpha <= rgb values. for a PM image "less |
956 | * than" shouldn't happen; fix "equal to" case by adding one to |
957 | * alpha channel (slightly inaccurate, but so is attempting to |
958 | * get back to NPM images, due to limits of integer precision) |
959 | */ |
960 | alpha = pixel >> 24; |
961 | if (alpha > 0 && alpha < 255) |
962 | pixel = (pixel & 0x00ffffff) | ((alpha + 1) << 24); |
963 | |
964 | #ifdef __BIG_ENDIAN |
965 | { |
966 | struct nouveau_drm *drm = nouveau_drm(dev); |
967 | |
968 | if (drm->client.device.info.chipset == 0x11) { |
969 | pixel = ((pixel & 0x000000ff) << 24) | |
970 | ((pixel & 0x0000ff00) << 8) | |
971 | ((pixel & 0x00ff0000) >> 8) | |
972 | ((pixel & 0xff000000) >> 24); |
973 | } |
974 | } |
975 | #endif |
976 | |
977 | nouveau_bo_wr32(dst, i, pixel); |
978 | } |
979 | } |
980 | |
981 | static int |
982 | nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, |
983 | uint32_t buffer_handle, uint32_t width, uint32_t height) |
984 | { |
985 | struct nouveau_drm *drm = nouveau_drm(crtc->dev); |
986 | struct drm_device *dev = drm->dev; |
987 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
988 | struct nouveau_bo *cursor = NULL; |
989 | struct drm_gem_object *gem; |
990 | int ret = 0; |
991 | |
992 | if (!buffer_handle) { |
993 | nv_crtc->cursor.hide(nv_crtc, true); |
994 | return 0; |
995 | } |
996 | |
997 | if (width != 64 || height != 64) |
998 | return -EINVAL; |
999 | |
1000 | gem = drm_gem_object_lookup(file_priv, buffer_handle); |
1001 | if (!gem) |
1002 | return -ENOENT; |
1003 | cursor = nouveau_gem_object(gem); |
1004 | |
1005 | ret = nouveau_bo_map(cursor); |
1006 | if (ret) |
1007 | goto out; |
1008 | |
1009 | if (drm->client.device.info.chipset >= 0x11) |
1010 | nv11_cursor_upload(dev, src: cursor, dst: nv_crtc->cursor.nvbo); |
1011 | else |
1012 | nv04_cursor_upload(dev, src: cursor, dst: nv_crtc->cursor.nvbo); |
1013 | |
1014 | nouveau_bo_unmap(cursor); |
1015 | nv_crtc->cursor.offset = nv_crtc->cursor.nvbo->offset; |
1016 | nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset); |
1017 | nv_crtc->cursor.show(nv_crtc, true); |
1018 | out: |
1019 | drm_gem_object_put(gem); |
1020 | return ret; |
1021 | } |
1022 | |
1023 | static int |
1024 | nv04_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) |
1025 | { |
1026 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
1027 | |
1028 | nv_crtc->cursor.set_pos(nv_crtc, x, y); |
1029 | return 0; |
1030 | } |
1031 | |
1032 | struct nv04_page_flip_state { |
1033 | struct list_head head; |
1034 | struct drm_pending_vblank_event *event; |
1035 | struct drm_crtc *crtc; |
1036 | int bpp, pitch; |
1037 | u64 offset; |
1038 | }; |
1039 | |
1040 | static int |
1041 | nv04_finish_page_flip(struct nouveau_channel *chan, |
1042 | struct nv04_page_flip_state *ps) |
1043 | { |
1044 | struct nouveau_fence_chan *fctx = chan->fence; |
1045 | struct nouveau_drm *drm = chan->drm; |
1046 | struct drm_device *dev = drm->dev; |
1047 | struct nv04_page_flip_state *s; |
1048 | unsigned long flags; |
1049 | |
1050 | spin_lock_irqsave(&dev->event_lock, flags); |
1051 | |
1052 | if (list_empty(head: &fctx->flip)) { |
1053 | NV_ERROR(drm, "unexpected pageflip\n" ); |
1054 | spin_unlock_irqrestore(lock: &dev->event_lock, flags); |
1055 | return -EINVAL; |
1056 | } |
1057 | |
1058 | s = list_first_entry(&fctx->flip, struct nv04_page_flip_state, head); |
1059 | if (s->event) { |
1060 | drm_crtc_arm_vblank_event(crtc: s->crtc, e: s->event); |
1061 | } else { |
1062 | /* Give up ownership of vblank for page-flipped crtc */ |
1063 | drm_crtc_vblank_put(crtc: s->crtc); |
1064 | } |
1065 | |
1066 | list_del(entry: &s->head); |
1067 | if (ps) |
1068 | *ps = *s; |
1069 | kfree(objp: s); |
1070 | |
1071 | spin_unlock_irqrestore(lock: &dev->event_lock, flags); |
1072 | return 0; |
1073 | } |
1074 | |
1075 | int |
1076 | nv04_flip_complete(struct nvif_event *event, void *argv, u32 argc) |
1077 | { |
1078 | struct nv04_display *disp = container_of(event, typeof(*disp), flip); |
1079 | struct nouveau_drm *drm = disp->drm; |
1080 | struct nouveau_channel *chan = drm->channel; |
1081 | struct nv04_page_flip_state state; |
1082 | |
1083 | if (!nv04_finish_page_flip(chan, ps: &state)) { |
1084 | nv_set_crtc_base(dev: drm->dev, head: drm_crtc_index(crtc: state.crtc), |
1085 | offset: state.offset + state.crtc->y * |
1086 | state.pitch + state.crtc->x * |
1087 | state.bpp / 8); |
1088 | } |
1089 | |
1090 | return NVIF_EVENT_KEEP; |
1091 | } |
1092 | |
1093 | static int |
1094 | nv04_page_flip_emit(struct nouveau_channel *chan, |
1095 | struct nouveau_bo *old_bo, |
1096 | struct nouveau_bo *new_bo, |
1097 | struct nv04_page_flip_state *s, |
1098 | struct nouveau_fence **pfence) |
1099 | { |
1100 | struct nouveau_fence_chan *fctx = chan->fence; |
1101 | struct nouveau_drm *drm = chan->drm; |
1102 | struct drm_device *dev = drm->dev; |
1103 | struct nvif_push *push = chan->chan.push; |
1104 | unsigned long flags; |
1105 | int ret; |
1106 | |
1107 | /* Queue it to the pending list */ |
1108 | spin_lock_irqsave(&dev->event_lock, flags); |
1109 | list_add_tail(new: &s->head, head: &fctx->flip); |
1110 | spin_unlock_irqrestore(lock: &dev->event_lock, flags); |
1111 | |
1112 | /* Synchronize with the old framebuffer */ |
1113 | ret = nouveau_fence_sync(old_bo, chan, false, false); |
1114 | if (ret) |
1115 | goto fail; |
1116 | |
1117 | /* Emit the pageflip */ |
1118 | ret = PUSH_WAIT(push, 2); |
1119 | if (ret) |
1120 | goto fail; |
1121 | |
1122 | PUSH_NVSQ(push, NV_SW, NV_SW_PAGE_FLIP, 0x00000000); |
1123 | PUSH_KICK(push); |
1124 | |
1125 | ret = nouveau_fence_new(pfence, chan); |
1126 | if (ret) |
1127 | goto fail; |
1128 | |
1129 | return 0; |
1130 | fail: |
1131 | spin_lock_irqsave(&dev->event_lock, flags); |
1132 | list_del(entry: &s->head); |
1133 | spin_unlock_irqrestore(lock: &dev->event_lock, flags); |
1134 | return ret; |
1135 | } |
1136 | |
1137 | static int |
1138 | nv04_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, |
1139 | struct drm_pending_vblank_event *event, u32 flags, |
1140 | struct drm_modeset_acquire_ctx *ctx) |
1141 | { |
1142 | const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; |
1143 | struct drm_device *dev = crtc->dev; |
1144 | struct nouveau_drm *drm = nouveau_drm(dev); |
1145 | struct drm_framebuffer *old_fb = crtc->primary->fb; |
1146 | struct nouveau_bo *old_bo = nouveau_gem_object(old_fb->obj[0]); |
1147 | struct nouveau_bo *new_bo = nouveau_gem_object(fb->obj[0]); |
1148 | struct nv04_page_flip_state *s; |
1149 | struct nouveau_channel *chan; |
1150 | struct nouveau_cli *cli; |
1151 | struct nouveau_fence *fence; |
1152 | struct nv04_display *dispnv04 = nv04_display(dev); |
1153 | struct nvif_push *push; |
1154 | int head = nouveau_crtc(crtc)->index; |
1155 | int ret; |
1156 | |
1157 | chan = drm->channel; |
1158 | if (!chan) |
1159 | return -ENODEV; |
1160 | cli = (void *)chan->user.client; |
1161 | push = chan->chan.push; |
1162 | |
1163 | s = kzalloc(size: sizeof(*s), GFP_KERNEL); |
1164 | if (!s) |
1165 | return -ENOMEM; |
1166 | |
1167 | if (new_bo != old_bo) { |
1168 | ret = nouveau_bo_pin(new_bo, NOUVEAU_GEM_DOMAIN_VRAM, true); |
1169 | if (ret) |
1170 | goto fail_free; |
1171 | } |
1172 | |
1173 | mutex_lock(&cli->mutex); |
1174 | ret = ttm_bo_reserve(&new_bo->bo, true, false, NULL); |
1175 | if (ret) |
1176 | goto fail_unpin; |
1177 | |
1178 | /* synchronise rendering channel with the kernel's channel */ |
1179 | ret = nouveau_fence_sync(new_bo, chan, false, true); |
1180 | if (ret) { |
1181 | ttm_bo_unreserve(&new_bo->bo); |
1182 | goto fail_unpin; |
1183 | } |
1184 | |
1185 | if (new_bo != old_bo) { |
1186 | ttm_bo_unreserve(&new_bo->bo); |
1187 | |
1188 | ret = ttm_bo_reserve(&old_bo->bo, true, false, NULL); |
1189 | if (ret) |
1190 | goto fail_unpin; |
1191 | } |
1192 | |
1193 | /* Initialize a page flip struct */ |
1194 | *s = (struct nv04_page_flip_state) |
1195 | { { }, event, crtc, fb->format->cpp[0] * 8, fb->pitches[0], |
1196 | new_bo->offset }; |
1197 | |
1198 | /* Keep vblanks on during flip, for the target crtc of this flip */ |
1199 | drm_crtc_vblank_get(crtc); |
1200 | |
1201 | /* Emit a page flip */ |
1202 | if (swap_interval) { |
1203 | ret = PUSH_WAIT(push, 8); |
1204 | if (ret) |
1205 | goto fail_unreserve; |
1206 | |
1207 | PUSH_NVSQ(push, NV05F, 0x012c, 0); |
1208 | PUSH_NVSQ(push, NV05F, 0x0134, head); |
1209 | PUSH_NVSQ(push, NV05F, 0x0100, 0); |
1210 | PUSH_NVSQ(push, NV05F, 0x0130, 0); |
1211 | } |
1212 | |
1213 | nouveau_bo_ref(new_bo, &dispnv04->image[head]); |
1214 | |
1215 | ret = nv04_page_flip_emit(chan, old_bo, new_bo, s, pfence: &fence); |
1216 | if (ret) |
1217 | goto fail_unreserve; |
1218 | mutex_unlock(lock: &cli->mutex); |
1219 | |
1220 | /* Update the crtc struct and cleanup */ |
1221 | crtc->primary->fb = fb; |
1222 | |
1223 | nouveau_bo_fence(old_bo, fence, false); |
1224 | ttm_bo_unreserve(&old_bo->bo); |
1225 | if (old_bo != new_bo) |
1226 | nouveau_bo_unpin(old_bo); |
1227 | nouveau_fence_unref(&fence); |
1228 | return 0; |
1229 | |
1230 | fail_unreserve: |
1231 | drm_crtc_vblank_put(crtc); |
1232 | ttm_bo_unreserve(&old_bo->bo); |
1233 | fail_unpin: |
1234 | mutex_unlock(lock: &cli->mutex); |
1235 | if (old_bo != new_bo) |
1236 | nouveau_bo_unpin(new_bo); |
1237 | fail_free: |
1238 | kfree(objp: s); |
1239 | return ret; |
1240 | } |
1241 | |
1242 | static const struct drm_crtc_funcs nv04_crtc_funcs = { |
1243 | .cursor_set = nv04_crtc_cursor_set, |
1244 | .cursor_move = nv04_crtc_cursor_move, |
1245 | .gamma_set = nv_crtc_gamma_set, |
1246 | .set_config = drm_crtc_helper_set_config, |
1247 | .page_flip = nv04_crtc_page_flip, |
1248 | .destroy = nv_crtc_destroy, |
1249 | .enable_vblank = nouveau_display_vblank_enable, |
1250 | .disable_vblank = nouveau_display_vblank_disable, |
1251 | .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, |
1252 | }; |
1253 | |
1254 | static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = { |
1255 | .dpms = nv_crtc_dpms, |
1256 | .prepare = nv_crtc_prepare, |
1257 | .commit = nv_crtc_commit, |
1258 | .mode_set = nv_crtc_mode_set, |
1259 | .mode_set_base = nv04_crtc_mode_set_base, |
1260 | .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic, |
1261 | .disable = nv_crtc_disable, |
1262 | .get_scanout_position = nouveau_display_scanoutpos, |
1263 | }; |
1264 | |
1265 | static const uint32_t modeset_formats[] = { |
1266 | DRM_FORMAT_XRGB8888, |
1267 | DRM_FORMAT_RGB565, |
1268 | DRM_FORMAT_XRGB1555, |
1269 | }; |
1270 | |
1271 | static const struct drm_plane_funcs nv04_primary_plane_funcs = { |
1272 | DRM_PLANE_NON_ATOMIC_FUNCS, |
1273 | }; |
1274 | |
1275 | static int |
1276 | nv04_crtc_vblank_handler(struct nvif_event *event, void *repv, u32 repc) |
1277 | { |
1278 | struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank); |
1279 | |
1280 | drm_crtc_handle_vblank(crtc: &nv_crtc->base); |
1281 | return NVIF_EVENT_KEEP; |
1282 | } |
1283 | |
1284 | int |
1285 | nv04_crtc_create(struct drm_device *dev, int crtc_num) |
1286 | { |
1287 | struct nouveau_display *disp = nouveau_display(dev); |
1288 | struct nouveau_crtc *nv_crtc; |
1289 | struct drm_plane *primary; |
1290 | int ret; |
1291 | |
1292 | nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL); |
1293 | if (!nv_crtc) |
1294 | return -ENOMEM; |
1295 | |
1296 | nv_crtc->lut.depth = 0; |
1297 | |
1298 | nv_crtc->index = crtc_num; |
1299 | nv_crtc->last_dpms = NV_DPMS_CLEARED; |
1300 | |
1301 | nv_crtc->save = nv_crtc_save; |
1302 | nv_crtc->restore = nv_crtc_restore; |
1303 | |
1304 | primary = __drm_universal_plane_alloc(dev, size: sizeof(*primary), offset: 0, possible_crtcs: 0, |
1305 | funcs: &nv04_primary_plane_funcs, |
1306 | formats: modeset_formats, |
1307 | ARRAY_SIZE(modeset_formats), NULL, |
1308 | plane_type: DRM_PLANE_TYPE_PRIMARY, NULL); |
1309 | if (IS_ERR(ptr: primary)) { |
1310 | ret = PTR_ERR(ptr: primary); |
1311 | kfree(objp: nv_crtc); |
1312 | return ret; |
1313 | } |
1314 | |
1315 | drm_crtc_init_with_planes(dev, crtc: &nv_crtc->base, primary, NULL, |
1316 | funcs: &nv04_crtc_funcs, NULL); |
1317 | drm_crtc_helper_add(crtc: &nv_crtc->base, funcs: &nv04_crtc_helper_funcs); |
1318 | drm_mode_crtc_set_gamma_size(crtc: &nv_crtc->base, gamma_size: 256); |
1319 | |
1320 | ret = nouveau_bo_new(&nouveau_drm(dev)->client, 64*64*4, 0x100, |
1321 | NOUVEAU_GEM_DOMAIN_VRAM, 0, 0x0000, NULL, NULL, |
1322 | &nv_crtc->cursor.nvbo); |
1323 | if (!ret) { |
1324 | ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, |
1325 | NOUVEAU_GEM_DOMAIN_VRAM, false); |
1326 | if (!ret) { |
1327 | ret = nouveau_bo_map(nv_crtc->cursor.nvbo); |
1328 | if (ret) |
1329 | nouveau_bo_unpin(nv_crtc->cursor.nvbo); |
1330 | } |
1331 | if (ret) |
1332 | nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); |
1333 | } |
1334 | |
1335 | nv04_cursor_init(nv_crtc); |
1336 | |
1337 | ret = nvif_head_ctor(&disp->disp, nv_crtc->base.name, nv_crtc->index, &nv_crtc->head); |
1338 | if (ret) |
1339 | return ret; |
1340 | |
1341 | return nvif_head_vblank_event_ctor(&nv_crtc->head, "kmsVbl" , nv04_crtc_vblank_handler, |
1342 | false, &nv_crtc->vblank); |
1343 | } |
1344 | |