]>
Commit | Line | Data |
---|---|---|
515de6b2 IM |
1 | /* |
2 | * Copyright 2013 Ilia Mirkin | |
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 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF | |
19 | * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
20 | * SOFTWARE. | |
21 | * | |
22 | * Implementation based on the pre-KMS implementation in xf86-video-nouveau, | |
23 | * written by Arthur Huillet. | |
24 | */ | |
25 | ||
26 | #include <drm/drmP.h> | |
27 | #include <drm/drm_crtc.h> | |
28 | #include <drm/drm_fourcc.h> | |
29 | ||
30 | #include "nouveau_drm.h" | |
31 | ||
32 | #include "nouveau_bo.h" | |
33 | #include "nouveau_connector.h" | |
34 | #include "nouveau_display.h" | |
35 | #include "nvreg.h" | |
36 | ||
37 | ||
38 | struct nouveau_plane { | |
39 | struct drm_plane base; | |
40 | bool flip; | |
41 | struct nouveau_bo *cur; | |
42 | ||
43 | struct { | |
44 | struct drm_property *colorkey; | |
45 | struct drm_property *contrast; | |
46 | struct drm_property *brightness; | |
47 | struct drm_property *hue; | |
48 | struct drm_property *saturation; | |
49 | struct drm_property *iturbt_709; | |
50 | } props; | |
51 | ||
52 | int colorkey; | |
53 | int contrast; | |
54 | int brightness; | |
55 | int hue; | |
56 | int saturation; | |
57 | int iturbt_709; | |
ab9b18a6 IM |
58 | |
59 | void (*set_params)(struct nouveau_plane *); | |
515de6b2 IM |
60 | }; |
61 | ||
62 | static uint32_t formats[] = { | |
7ffb0781 | 63 | DRM_FORMAT_YUYV, |
515de6b2 | 64 | DRM_FORMAT_UYVY, |
efffa984 | 65 | DRM_FORMAT_NV12, |
515de6b2 IM |
66 | }; |
67 | ||
68 | /* Sine can be approximated with | |
69 | * http://en.wikipedia.org/wiki/Bhaskara_I's_sine_approximation_formula | |
70 | * sin(x degrees) ~= 4 x (180 - x) / (40500 - x (180 - x) ) | |
71 | * Note that this only works for the range [0, 180]. | |
72 | * Also note that sin(x) == -sin(x - 180) | |
73 | */ | |
74 | static inline int | |
75 | sin_mul(int degrees, int factor) | |
76 | { | |
77 | if (degrees > 180) { | |
78 | degrees -= 180; | |
79 | factor *= -1; | |
80 | } | |
81 | return factor * 4 * degrees * (180 - degrees) / | |
82 | (40500 - degrees * (180 - degrees)); | |
83 | } | |
84 | ||
85 | /* cos(x) = sin(x + 90) */ | |
86 | static inline int | |
87 | cos_mul(int degrees, int factor) | |
88 | { | |
89 | return sin_mul((degrees + 90) % 360, factor); | |
90 | } | |
91 | ||
92 | static int | |
93 | nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, | |
94 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, | |
95 | unsigned int crtc_w, unsigned int crtc_h, | |
96 | uint32_t src_x, uint32_t src_y, | |
97 | uint32_t src_w, uint32_t src_h) | |
98 | { | |
967e7bde | 99 | struct nvif_device *dev = &nouveau_drm(plane->dev)->device; |
5ee932d0 FF |
100 | struct nouveau_plane *nv_plane = |
101 | container_of(plane, struct nouveau_plane, base); | |
515de6b2 IM |
102 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); |
103 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | |
104 | struct nouveau_bo *cur = nv_plane->cur; | |
105 | bool flip = nv_plane->flip; | |
515de6b2 IM |
106 | int soff = NV_PCRTC0_SIZE * nv_crtc->index; |
107 | int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index; | |
92e5b0a2 IM |
108 | int format, ret; |
109 | ||
110 | /* Source parameters given in 16.16 fixed point, ignore fractional. */ | |
111 | src_x >>= 16; | |
112 | src_y >>= 16; | |
113 | src_w >>= 16; | |
114 | src_h >>= 16; | |
115 | ||
116 | format = ALIGN(src_w * 4, 0x100); | |
515de6b2 IM |
117 | |
118 | if (format > 0xffff) | |
050828e9 IM |
119 | return -ERANGE; |
120 | ||
967e7bde | 121 | if (dev->info.chipset >= 0x30) { |
050828e9 IM |
122 | if (crtc_w < (src_w >> 1) || crtc_h < (src_h >> 1)) |
123 | return -ERANGE; | |
124 | } else { | |
125 | if (crtc_w < (src_w >> 3) || crtc_h < (src_h >> 3)) | |
126 | return -ERANGE; | |
127 | } | |
515de6b2 | 128 | |
ad76b3f7 | 129 | ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false); |
515de6b2 IM |
130 | if (ret) |
131 | return ret; | |
132 | ||
133 | nv_plane->cur = nv_fb->nvbo; | |
134 | ||
db2bec18 BS |
135 | nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY); |
136 | nvif_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0); | |
515de6b2 | 137 | |
db2bec18 BS |
138 | nvif_wr32(dev, NV_PVIDEO_BASE(flip), 0); |
139 | nvif_wr32(dev, NV_PVIDEO_OFFSET_BUFF(flip), nv_fb->nvbo->bo.offset); | |
140 | nvif_wr32(dev, NV_PVIDEO_SIZE_IN(flip), src_h << 16 | src_w); | |
141 | nvif_wr32(dev, NV_PVIDEO_POINT_IN(flip), src_y << 16 | src_x); | |
142 | nvif_wr32(dev, NV_PVIDEO_DS_DX(flip), (src_w << 20) / crtc_w); | |
143 | nvif_wr32(dev, NV_PVIDEO_DT_DY(flip), (src_h << 20) / crtc_h); | |
144 | nvif_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x); | |
145 | nvif_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w); | |
515de6b2 | 146 | |
7ffb0781 | 147 | if (fb->pixel_format != DRM_FORMAT_UYVY) |
515de6b2 | 148 | format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8; |
7ffb0781 | 149 | if (fb->pixel_format == DRM_FORMAT_NV12) |
515de6b2 | 150 | format |= NV_PVIDEO_FORMAT_PLANAR; |
515de6b2 IM |
151 | if (nv_plane->iturbt_709) |
152 | format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709; | |
153 | if (nv_plane->colorkey & (1 << 24)) | |
154 | format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY; | |
155 | ||
156 | if (fb->pixel_format == DRM_FORMAT_NV12) { | |
db2bec18 BS |
157 | nvif_wr32(dev, NV_PVIDEO_UVPLANE_BASE(flip), 0); |
158 | nvif_wr32(dev, NV_PVIDEO_UVPLANE_OFFSET_BUFF(flip), | |
515de6b2 IM |
159 | nv_fb->nvbo->bo.offset + fb->offsets[1]); |
160 | } | |
db2bec18 BS |
161 | nvif_wr32(dev, NV_PVIDEO_FORMAT(flip), format); |
162 | nvif_wr32(dev, NV_PVIDEO_STOP, 0); | |
515de6b2 | 163 | /* TODO: wait for vblank? */ |
db2bec18 | 164 | nvif_wr32(dev, NV_PVIDEO_BUFFER, flip ? 0x10 : 0x1); |
515de6b2 IM |
165 | nv_plane->flip = !flip; |
166 | ||
167 | if (cur) | |
168 | nouveau_bo_unpin(cur); | |
169 | ||
170 | return 0; | |
171 | } | |
172 | ||
173 | static int | |
174 | nv10_disable_plane(struct drm_plane *plane) | |
175 | { | |
967e7bde | 176 | struct nvif_device *dev = &nouveau_drm(plane->dev)->device; |
5ee932d0 FF |
177 | struct nouveau_plane *nv_plane = |
178 | container_of(plane, struct nouveau_plane, base); | |
515de6b2 | 179 | |
db2bec18 | 180 | nvif_wr32(dev, NV_PVIDEO_STOP, 1); |
515de6b2 IM |
181 | if (nv_plane->cur) { |
182 | nouveau_bo_unpin(nv_plane->cur); | |
183 | nv_plane->cur = NULL; | |
184 | } | |
185 | ||
186 | return 0; | |
187 | } | |
188 | ||
189 | static void | |
ab9b18a6 | 190 | nv_destroy_plane(struct drm_plane *plane) |
515de6b2 | 191 | { |
ab9b18a6 | 192 | plane->funcs->disable_plane(plane); |
515de6b2 IM |
193 | drm_plane_cleanup(plane); |
194 | kfree(plane); | |
195 | } | |
196 | ||
197 | static void | |
198 | nv10_set_params(struct nouveau_plane *plane) | |
199 | { | |
967e7bde | 200 | struct nvif_device *dev = &nouveau_drm(plane->base.dev)->device; |
515de6b2 IM |
201 | u32 luma = (plane->brightness - 512) << 16 | plane->contrast; |
202 | u32 chroma = ((sin_mul(plane->hue, plane->saturation) & 0xffff) << 16) | | |
203 | (cos_mul(plane->hue, plane->saturation) & 0xffff); | |
204 | u32 format = 0; | |
205 | ||
db2bec18 BS |
206 | nvif_wr32(dev, NV_PVIDEO_LUMINANCE(0), luma); |
207 | nvif_wr32(dev, NV_PVIDEO_LUMINANCE(1), luma); | |
208 | nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(0), chroma); | |
209 | nvif_wr32(dev, NV_PVIDEO_CHROMINANCE(1), chroma); | |
210 | nvif_wr32(dev, NV_PVIDEO_COLOR_KEY, plane->colorkey & 0xffffff); | |
515de6b2 IM |
211 | |
212 | if (plane->cur) { | |
213 | if (plane->iturbt_709) | |
214 | format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709; | |
215 | if (plane->colorkey & (1 << 24)) | |
216 | format |= NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY; | |
db2bec18 | 217 | nvif_mask(dev, NV_PVIDEO_FORMAT(plane->flip), |
515de6b2 IM |
218 | NV_PVIDEO_FORMAT_MATRIX_ITURBT709 | |
219 | NV_PVIDEO_FORMAT_DISPLAY_COLOR_KEY, | |
220 | format); | |
221 | } | |
222 | } | |
223 | ||
224 | static int | |
ab9b18a6 IM |
225 | nv_set_property(struct drm_plane *plane, |
226 | struct drm_property *property, | |
227 | uint64_t value) | |
515de6b2 | 228 | { |
5ee932d0 FF |
229 | struct nouveau_plane *nv_plane = |
230 | container_of(plane, struct nouveau_plane, base); | |
515de6b2 IM |
231 | |
232 | if (property == nv_plane->props.colorkey) | |
233 | nv_plane->colorkey = value; | |
234 | else if (property == nv_plane->props.contrast) | |
235 | nv_plane->contrast = value; | |
236 | else if (property == nv_plane->props.brightness) | |
237 | nv_plane->brightness = value; | |
238 | else if (property == nv_plane->props.hue) | |
239 | nv_plane->hue = value; | |
240 | else if (property == nv_plane->props.saturation) | |
241 | nv_plane->saturation = value; | |
242 | else if (property == nv_plane->props.iturbt_709) | |
243 | nv_plane->iturbt_709 = value; | |
244 | else | |
245 | return -EINVAL; | |
246 | ||
ab9b18a6 IM |
247 | if (nv_plane->set_params) |
248 | nv_plane->set_params(nv_plane); | |
515de6b2 IM |
249 | return 0; |
250 | } | |
251 | ||
252 | static const struct drm_plane_funcs nv10_plane_funcs = { | |
253 | .update_plane = nv10_update_plane, | |
254 | .disable_plane = nv10_disable_plane, | |
ab9b18a6 IM |
255 | .set_property = nv_set_property, |
256 | .destroy = nv_destroy_plane, | |
515de6b2 IM |
257 | }; |
258 | ||
259 | static void | |
260 | nv10_overlay_init(struct drm_device *device) | |
261 | { | |
fa2bade9 | 262 | struct nouveau_drm *drm = nouveau_drm(device); |
515de6b2 | 263 | struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); |
45e3743a | 264 | unsigned int num_formats = ARRAY_SIZE(formats); |
515de6b2 IM |
265 | int ret; |
266 | ||
267 | if (!plane) | |
268 | return; | |
269 | ||
967e7bde | 270 | switch (drm->device.info.chipset) { |
efffa984 IM |
271 | case 0x10: |
272 | case 0x11: | |
273 | case 0x15: | |
274 | case 0x1a: | |
275 | case 0x20: | |
7ffb0781 | 276 | num_formats = 2; |
efffa984 IM |
277 | break; |
278 | } | |
279 | ||
515de6b2 IM |
280 | ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */, |
281 | &nv10_plane_funcs, | |
efffa984 | 282 | formats, num_formats, false); |
515de6b2 IM |
283 | if (ret) |
284 | goto err; | |
285 | ||
286 | /* Set up the plane properties */ | |
287 | plane->props.colorkey = drm_property_create_range( | |
288 | device, 0, "colorkey", 0, 0x01ffffff); | |
289 | plane->props.contrast = drm_property_create_range( | |
290 | device, 0, "contrast", 0, 8192 - 1); | |
291 | plane->props.brightness = drm_property_create_range( | |
292 | device, 0, "brightness", 0, 1024); | |
293 | plane->props.hue = drm_property_create_range( | |
294 | device, 0, "hue", 0, 359); | |
295 | plane->props.saturation = drm_property_create_range( | |
296 | device, 0, "saturation", 0, 8192 - 1); | |
297 | plane->props.iturbt_709 = drm_property_create_range( | |
298 | device, 0, "iturbt_709", 0, 1); | |
299 | if (!plane->props.colorkey || | |
300 | !plane->props.contrast || | |
301 | !plane->props.brightness || | |
302 | !plane->props.hue || | |
303 | !plane->props.saturation || | |
304 | !plane->props.iturbt_709) | |
305 | goto cleanup; | |
306 | ||
307 | plane->colorkey = 0; | |
308 | drm_object_attach_property(&plane->base.base, | |
309 | plane->props.colorkey, plane->colorkey); | |
310 | ||
311 | plane->contrast = 0x1000; | |
312 | drm_object_attach_property(&plane->base.base, | |
313 | plane->props.contrast, plane->contrast); | |
314 | ||
315 | plane->brightness = 512; | |
316 | drm_object_attach_property(&plane->base.base, | |
317 | plane->props.brightness, plane->brightness); | |
318 | ||
319 | plane->hue = 0; | |
320 | drm_object_attach_property(&plane->base.base, | |
321 | plane->props.hue, plane->hue); | |
322 | ||
323 | plane->saturation = 0x1000; | |
324 | drm_object_attach_property(&plane->base.base, | |
325 | plane->props.saturation, plane->saturation); | |
326 | ||
327 | plane->iturbt_709 = 0; | |
328 | drm_object_attach_property(&plane->base.base, | |
329 | plane->props.iturbt_709, plane->iturbt_709); | |
330 | ||
ab9b18a6 | 331 | plane->set_params = nv10_set_params; |
515de6b2 | 332 | nv10_set_params(plane); |
ab9b18a6 IM |
333 | nv10_disable_plane(&plane->base); |
334 | return; | |
335 | cleanup: | |
336 | drm_plane_cleanup(&plane->base); | |
337 | err: | |
338 | kfree(plane); | |
fa2bade9 | 339 | NV_ERROR(drm, "Failed to create plane\n"); |
ab9b18a6 IM |
340 | } |
341 | ||
342 | static int | |
343 | nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, | |
344 | struct drm_framebuffer *fb, int crtc_x, int crtc_y, | |
345 | unsigned int crtc_w, unsigned int crtc_h, | |
346 | uint32_t src_x, uint32_t src_y, | |
347 | uint32_t src_w, uint32_t src_h) | |
348 | { | |
967e7bde | 349 | struct nvif_device *dev = &nouveau_drm(plane->dev)->device; |
5ee932d0 FF |
350 | struct nouveau_plane *nv_plane = |
351 | container_of(plane, struct nouveau_plane, base); | |
ab9b18a6 IM |
352 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); |
353 | struct nouveau_bo *cur = nv_plane->cur; | |
354 | uint32_t overlay = 1; | |
355 | int brightness = (nv_plane->brightness - 512) * 62 / 512; | |
356 | int pitch, ret, i; | |
357 | ||
358 | /* Source parameters given in 16.16 fixed point, ignore fractional. */ | |
359 | src_x >>= 16; | |
360 | src_y >>= 16; | |
361 | src_w >>= 16; | |
362 | src_h >>= 16; | |
363 | ||
364 | pitch = ALIGN(src_w * 4, 0x100); | |
365 | ||
366 | if (pitch > 0xffff) | |
367 | return -ERANGE; | |
368 | ||
369 | /* TODO: Compute an offset? Not sure how to do this for YUYV. */ | |
370 | if (src_x != 0 || src_y != 0) | |
371 | return -ERANGE; | |
372 | ||
373 | if (crtc_w < src_w || crtc_h < src_h) | |
374 | return -ERANGE; | |
375 | ||
ad76b3f7 | 376 | ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM, false); |
ab9b18a6 IM |
377 | if (ret) |
378 | return ret; | |
379 | ||
380 | nv_plane->cur = nv_fb->nvbo; | |
381 | ||
db2bec18 BS |
382 | nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0); |
383 | nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0); | |
384 | nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0); | |
ab9b18a6 IM |
385 | |
386 | for (i = 0; i < 2; i++) { | |
db2bec18 | 387 | nvif_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i, |
ab9b18a6 | 388 | nv_fb->nvbo->bo.offset); |
db2bec18 BS |
389 | nvif_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, pitch); |
390 | nvif_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0); | |
ab9b18a6 | 391 | } |
db2bec18 BS |
392 | nvif_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x); |
393 | nvif_wr32(dev, NV_PVIDEO_WINDOW_SIZE, crtc_h << 16 | crtc_w); | |
394 | nvif_wr32(dev, NV_PVIDEO_STEP_SIZE, | |
ab9b18a6 IM |
395 | (uint32_t)(((src_h - 1) << 11) / (crtc_h - 1)) << 16 | (uint32_t)(((src_w - 1) << 11) / (crtc_w - 1))); |
396 | ||
397 | /* It should be possible to convert hue/contrast to this */ | |
db2bec18 BS |
398 | nvif_wr32(dev, NV_PVIDEO_RED_CSC_OFFSET, 0x69 - brightness); |
399 | nvif_wr32(dev, NV_PVIDEO_GREEN_CSC_OFFSET, 0x3e + brightness); | |
400 | nvif_wr32(dev, NV_PVIDEO_BLUE_CSC_OFFSET, 0x89 - brightness); | |
401 | nvif_wr32(dev, NV_PVIDEO_CSC_ADJUST, 0); | |
ab9b18a6 | 402 | |
db2bec18 BS |
403 | nvif_wr32(dev, NV_PVIDEO_CONTROL_Y, 0x001); /* (BLUR_ON, LINE_HALF) */ |
404 | nvif_wr32(dev, NV_PVIDEO_CONTROL_X, 0x111); /* (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */ | |
ab9b18a6 | 405 | |
db2bec18 BS |
406 | nvif_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03); |
407 | nvif_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38); | |
ab9b18a6 | 408 | |
db2bec18 | 409 | nvif_wr32(dev, NV_PVIDEO_KEY, nv_plane->colorkey); |
ab9b18a6 IM |
410 | |
411 | if (nv_plane->colorkey & (1 << 24)) | |
412 | overlay |= 0x10; | |
413 | if (fb->pixel_format == DRM_FORMAT_YUYV) | |
414 | overlay |= 0x100; | |
415 | ||
db2bec18 | 416 | nvif_wr32(dev, NV_PVIDEO_OVERLAY, overlay); |
ab9b18a6 | 417 | |
db2bec18 | 418 | nvif_wr32(dev, NV_PVIDEO_SU_STATE, nvif_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16)); |
ab9b18a6 IM |
419 | |
420 | if (cur) | |
421 | nouveau_bo_unpin(cur); | |
422 | ||
423 | return 0; | |
424 | } | |
425 | ||
426 | static int | |
427 | nv04_disable_plane(struct drm_plane *plane) | |
428 | { | |
967e7bde | 429 | struct nvif_device *dev = &nouveau_drm(plane->dev)->device; |
5ee932d0 FF |
430 | struct nouveau_plane *nv_plane = |
431 | container_of(plane, struct nouveau_plane, base); | |
ab9b18a6 | 432 | |
db2bec18 BS |
433 | nvif_mask(dev, NV_PVIDEO_OVERLAY, 1, 0); |
434 | nvif_wr32(dev, NV_PVIDEO_OE_STATE, 0); | |
435 | nvif_wr32(dev, NV_PVIDEO_SU_STATE, 0); | |
436 | nvif_wr32(dev, NV_PVIDEO_RM_STATE, 0); | |
ab9b18a6 IM |
437 | if (nv_plane->cur) { |
438 | nouveau_bo_unpin(nv_plane->cur); | |
439 | nv_plane->cur = NULL; | |
440 | } | |
441 | ||
442 | return 0; | |
443 | } | |
444 | ||
445 | static const struct drm_plane_funcs nv04_plane_funcs = { | |
446 | .update_plane = nv04_update_plane, | |
447 | .disable_plane = nv04_disable_plane, | |
448 | .set_property = nv_set_property, | |
449 | .destroy = nv_destroy_plane, | |
450 | }; | |
451 | ||
452 | static void | |
453 | nv04_overlay_init(struct drm_device *device) | |
454 | { | |
fa2bade9 | 455 | struct nouveau_drm *drm = nouveau_drm(device); |
ab9b18a6 IM |
456 | struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); |
457 | int ret; | |
458 | ||
459 | if (!plane) | |
460 | return; | |
461 | ||
462 | ret = drm_plane_init(device, &plane->base, 1 /* single crtc */, | |
463 | &nv04_plane_funcs, | |
464 | formats, 2, false); | |
465 | if (ret) | |
466 | goto err; | |
467 | ||
468 | /* Set up the plane properties */ | |
469 | plane->props.colorkey = drm_property_create_range( | |
470 | device, 0, "colorkey", 0, 0x01ffffff); | |
471 | plane->props.brightness = drm_property_create_range( | |
472 | device, 0, "brightness", 0, 1024); | |
473 | if (!plane->props.colorkey || | |
474 | !plane->props.brightness) | |
475 | goto cleanup; | |
476 | ||
477 | plane->colorkey = 0; | |
478 | drm_object_attach_property(&plane->base.base, | |
479 | plane->props.colorkey, plane->colorkey); | |
480 | ||
481 | plane->brightness = 512; | |
482 | drm_object_attach_property(&plane->base.base, | |
483 | plane->props.brightness, plane->brightness); | |
484 | ||
485 | nv04_disable_plane(&plane->base); | |
515de6b2 IM |
486 | return; |
487 | cleanup: | |
488 | drm_plane_cleanup(&plane->base); | |
489 | err: | |
490 | kfree(plane); | |
fa2bade9 | 491 | NV_ERROR(drm, "Failed to create plane\n"); |
515de6b2 IM |
492 | } |
493 | ||
494 | void | |
495 | nouveau_overlay_init(struct drm_device *device) | |
496 | { | |
967e7bde BS |
497 | struct nvif_device *dev = &nouveau_drm(device)->device; |
498 | if (dev->info.chipset < 0x10) | |
ab9b18a6 | 499 | nv04_overlay_init(device); |
967e7bde | 500 | else if (dev->info.chipset <= 0x40) |
515de6b2 IM |
501 | nv10_overlay_init(device); |
502 | } |