Set memory attributes on page
[pscnv.git] / pscnv / nouveau_display.c
blob1d51c365e4ad087465dcf30b1b9c3be7b36a338d
1 /*
2 * Copyright (C) 2008 Maarten Maathuis.
3 * All Rights Reserved.
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"
34 static void
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);
43 kfree(fb);
46 static int
47 nouveau_user_framebuffer_create_handle(struct drm_framebuffer *drm_fb,
48 struct drm_file *file_priv,
49 unsigned int *handle)
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
62 int
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)
65 #else
66 int
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)
69 #endif
71 int ret;
73 ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs);
74 if (ret) {
75 return ret;
78 drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd);
79 nouveau_fb->nvbo = nvbo;
80 return 0;
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)
89 #else
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)
94 #endif
96 struct nouveau_framebuffer *nouveau_fb;
97 struct drm_gem_object *gem;
98 int ret;
100 #ifdef PSCNV_KAPI_DRM_MODE_FB_CMD2
101 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
102 #else
103 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
104 #endif
105 if (!gem)
106 return ERR_PTR(-ENOENT);
108 nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
109 if (!nouveau_fb)
110 return ERR_PTR(-ENOMEM);
112 ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, gem->driver_private);
113 if (ret) {
114 drm_gem_object_unreference(gem);
115 return ERR_PTR(ret);
118 return &nouveau_fb->base;
121 #ifdef __linux__
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,
128 #else
130 static int
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);
136 if (IS_ERR(ret)) {
137 *res = NULL;
138 return PTR_ERR(ret);
140 *res = ret;
141 return 0;
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,
149 #endif
151 struct nouveau_drm_prop_enum_list {
152 u8 gen_mask;
153 int type;
154 char *name;
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); \
183 int c = 0; \
184 while (l->gen_mask) { \
185 if (l->gen_mask & (1 << (gen))) \
186 c++; \
187 l++; \
189 if (c) { \
190 p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c); \
191 l = (list); \
192 c = 0; \
193 while (p && l->gen_mask) { \
194 if (l->gen_mask & (1 << (gen))) { \
195 drm_property_add_enum(p, c, l->type, l->name); \
196 c++; \
198 l++; \
201 } while(0)
203 #if 1 // TODO: Add KAPI test
204 struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
205 const char *name,
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);
213 if (!property)
214 return NULL;
216 property->values[0] = min;
217 property->values[1] = max;
219 return property;
221 #endif
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;
228 int ret, gen;
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)
235 gen = 0;
236 else
237 if (dev_priv->card_type < NV_D0)
238 gen = 1;
239 else
240 gen = 2;
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);
252 if (gen == 1) {
253 disp->vibrant_hue_property =
254 drm_property_create(dev, DRM_MODE_PROP_RANGE,
255 "vibrant hue", 2);
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 */
266 #ifdef __DECONST
267 dev->mode_config.funcs = __DECONST(struct drm_mode_config_funcs *, &nouveau_mode_config_funcs);
268 #else
269 dev->mode_config.funcs = (void*)&nouveau_mode_config_funcs;
270 #endif
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;
278 } else
279 if (dev_priv->card_type < NV_50) {
280 dev->mode_config.max_width = 4096;
281 dev->mode_config.max_height = 4096;
282 } else {
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;
290 #endif
292 ret = disp->create(dev);
293 return ret;
296 void
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);
304 disp->destroy(dev);
306 drm_kms_helper_poll_fini(dev);
307 drm_mode_config_cleanup(dev);