2 * Copyright (C) 2008 Maarten Maathuis.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "nouveau_drv.h"
28 #include "drm_crtc_helper.h"
29 #include "nouveau_fb.h"
30 #include "nouveau_fbcon.h"
31 #include "nouveau_connector.h"
32 #include "pscnv_kapi.h"
35 nouveau_user_framebuffer_destroy(struct drm_framebuffer
*drm_fb
)
37 struct nouveau_framebuffer
*fb
= nouveau_framebuffer(drm_fb
);
39 if (fb
->nvbo
&& fb
->nvbo
->gem
)
40 drm_gem_object_unreference_unlocked(fb
->nvbo
->gem
);
42 drm_framebuffer_cleanup(drm_fb
);
47 nouveau_user_framebuffer_create_handle(struct drm_framebuffer
*drm_fb
,
48 struct drm_file
*file_priv
,
51 struct nouveau_framebuffer
*fb
= nouveau_framebuffer(drm_fb
);
53 return drm_gem_handle_create(file_priv
, fb
->nvbo
->gem
, handle
);
56 static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs
= {
57 .destroy
= nouveau_user_framebuffer_destroy
,
58 .create_handle
= nouveau_user_framebuffer_create_handle
,
61 #ifdef PSCNV_KAPI_DRM_MODE_FB_CMD2
63 nouveau_framebuffer_init(struct drm_device
*dev
, struct nouveau_framebuffer
*nouveau_fb
,
64 struct drm_mode_fb_cmd2
*mode_cmd
, struct pscnv_bo
*nvbo
)
67 nouveau_framebuffer_init(struct drm_device
*dev
, struct nouveau_framebuffer
*nouveau_fb
,
68 struct drm_mode_fb_cmd
*mode_cmd
, struct pscnv_bo
*nvbo
)
73 ret
= drm_framebuffer_init(dev
, &nouveau_fb
->base
, &nouveau_framebuffer_funcs
);
78 drm_helper_mode_fill_fb_struct(&nouveau_fb
->base
, mode_cmd
);
79 nouveau_fb
->nvbo
= nvbo
;
84 #ifdef PSCNV_KAPI_DRM_MODE_FB_CMD2
85 static struct drm_framebuffer
*
86 nouveau_user_framebuffer_create(struct drm_device
*dev
,
87 struct drm_file
*file_priv
,
88 struct drm_mode_fb_cmd2
*mode_cmd
)
90 static struct drm_framebuffer
*
91 nouveau_user_framebuffer_create(struct drm_device
*dev
,
92 struct drm_file
*file_priv
,
93 struct drm_mode_fb_cmd
*mode_cmd
)
96 struct nouveau_framebuffer
*nouveau_fb
;
97 struct drm_gem_object
*gem
;
100 #ifdef PSCNV_KAPI_DRM_MODE_FB_CMD2
101 gem
= drm_gem_object_lookup(dev
, file_priv
, mode_cmd
->handles
[0]);
103 gem
= drm_gem_object_lookup(dev
, file_priv
, mode_cmd
->handle
);
106 return ERR_PTR(-ENOENT
);
108 nouveau_fb
= kzalloc(sizeof(struct nouveau_framebuffer
), GFP_KERNEL
);
110 return ERR_PTR(-ENOMEM
);
112 ret
= nouveau_framebuffer_init(dev
, nouveau_fb
, mode_cmd
, gem
->driver_private
);
114 drm_gem_object_unreference(gem
);
118 return &nouveau_fb
->base
;
123 const struct drm_mode_config_funcs nouveau_mode_config_funcs
= {
124 .fb_create
= nouveau_user_framebuffer_create
,
125 .output_poll_changed
= nouveau_fbcon_output_poll_changed
,
131 nouveau_user_framebuffer_create_bsd(struct drm_device
*dev
,
132 struct drm_file
*filp
, struct drm_mode_fb_cmd2
*mode_cmd
,
133 struct drm_framebuffer
**res
)
135 struct drm_framebuffer
*ret
= nouveau_user_framebuffer_create(dev
, filp
, mode_cmd
);
144 const struct drm_mode_config_funcs nouveau_mode_config_funcs
= {
145 .fb_create
= nouveau_user_framebuffer_create_bsd
,
146 .output_poll_changed
= nouveau_fbcon_output_poll_changed
,
151 struct nouveau_drm_prop_enum_list
{
157 static struct nouveau_drm_prop_enum_list underscan
[] = {
158 { 6, UNDERSCAN_AUTO
, "auto" },
159 { 6, UNDERSCAN_OFF
, "off" },
160 { 6, UNDERSCAN_ON
, "on" },
164 static struct nouveau_drm_prop_enum_list dither_mode
[] = {
165 { 7, DITHERING_MODE_AUTO
, "auto" },
166 { 7, DITHERING_MODE_OFF
, "off" },
167 { 1, DITHERING_MODE_ON
, "on" },
168 { 6, DITHERING_MODE_STATIC2X2
, "static 2x2" },
169 { 6, DITHERING_MODE_DYNAMIC2X2
, "dynamic 2x2" },
170 { 4, DITHERING_MODE_TEMPORAL
, "temporal" },
174 static struct nouveau_drm_prop_enum_list dither_depth
[] = {
175 { 6, DITHERING_DEPTH_AUTO
, "auto" },
176 { 6, DITHERING_DEPTH_6BPC
, "6 bpc" },
177 { 6, DITHERING_DEPTH_8BPC
, "8 bpc" },
181 #define PROP_ENUM(p,gen,n,list) do { \
182 struct nouveau_drm_prop_enum_list *l = (list); \
184 while (l->gen_mask) { \
185 if (l->gen_mask & (1 << (gen))) \
190 p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c); \
193 while (p && l->gen_mask) { \
194 if (l->gen_mask & (1 << (gen))) { \
195 drm_property_add_enum(p, c, l->type, l->name); \
203 #if 1 // TODO: Add KAPI test
204 struct drm_property
*drm_property_create_range(struct drm_device
*dev
, int flags
,
206 uint64_t min
, uint64_t max
)
208 struct drm_property
*property
;
210 flags
|= DRM_MODE_PROP_RANGE
;
212 property
= drm_property_create(dev
, flags
, name
, 2);
216 property
->values
[0] = min
;
217 property
->values
[1] = max
;
224 nouveau_display_create(struct drm_device
*dev
)
226 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
227 struct nouveau_display_engine
*disp
= &dev_priv
->engine
.display
;
230 drm_mode_config_init(dev
);
231 drm_mode_create_scaling_mode_property(dev
);
232 drm_mode_create_dvi_i_properties(dev
);
234 if (dev_priv
->card_type
< NV_50
)
237 if (dev_priv
->card_type
< NV_D0
)
242 PROP_ENUM(disp
->dithering_mode
, gen
, "dithering mode", dither_mode
);
243 PROP_ENUM(disp
->dithering_depth
, gen
, "dithering depth", dither_depth
);
244 PROP_ENUM(disp
->underscan_property
, gen
, "underscan", underscan
);
246 disp
->underscan_hborder_property
=
247 drm_property_create_range(dev
, 0, "underscan hborder", 0, 128);
249 disp
->underscan_vborder_property
=
250 drm_property_create_range(dev
, 0, "underscan vborder", 0, 128);
253 disp
->vibrant_hue_property
=
254 drm_property_create(dev
, DRM_MODE_PROP_RANGE
,
256 disp
->vibrant_hue_property
->values
[0] = 0;
257 disp
->vibrant_hue_property
->values
[1] = 180; /* -90..+90 */
259 disp
->color_vibrance_property
=
260 drm_property_create(dev
, DRM_MODE_PROP_RANGE
,
261 "color vibrance", 2);
262 disp
->color_vibrance_property
->values
[0] = 0;
263 disp
->color_vibrance_property
->values
[1] = 200; /* -100..+100 */
267 dev
->mode_config
.funcs
= __DECONST(struct drm_mode_config_funcs
*, &nouveau_mode_config_funcs
);
269 dev
->mode_config
.funcs
= (void*)&nouveau_mode_config_funcs
;
271 dev
->mode_config
.fb_base
= dev_priv
->fb_phys
;
273 dev
->mode_config
.min_width
= 0;
274 dev
->mode_config
.min_height
= 0;
275 if (dev_priv
->card_type
< NV_10
) {
276 dev
->mode_config
.max_width
= 2048;
277 dev
->mode_config
.max_height
= 2048;
279 if (dev_priv
->card_type
< NV_50
) {
280 dev
->mode_config
.max_width
= 4096;
281 dev
->mode_config
.max_height
= 4096;
283 dev
->mode_config
.max_width
= 8192;
284 dev
->mode_config
.max_height
= 8192;
287 #ifdef DRM_CAP_DUMB_PREFERRED_DEPTH
288 dev
->mode_config
.preferred_depth
= 24;
289 dev
->mode_config
.prefer_shadow
= 1;
292 ret
= disp
->create(dev
);
297 nouveau_display_destroy(struct drm_device
*dev
)
299 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
300 struct nouveau_display_engine
*disp
= &dev_priv
->engine
.display
;
302 drm_vblank_cleanup(dev
);
306 drm_kms_helper_poll_fini(dev
);
307 drm_mode_config_cleanup(dev
);