aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_display.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c198
1 files changed, 189 insertions, 9 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index b12fd2c8081..3cb52bc52b2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -32,6 +32,8 @@
32#include "nouveau_hw.h" 32#include "nouveau_hw.h"
33#include "nouveau_crtc.h" 33#include "nouveau_crtc.h"
34#include "nouveau_dma.h" 34#include "nouveau_dma.h"
35#include "nouveau_connector.h"
36#include "nouveau_gpio.h"
35#include "nv50_display.h" 37#include "nv50_display.h"
36 38
37static void 39static void
@@ -64,7 +66,7 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
64int 66int
65nouveau_framebuffer_init(struct drm_device *dev, 67nouveau_framebuffer_init(struct drm_device *dev,
66 struct nouveau_framebuffer *nv_fb, 68 struct nouveau_framebuffer *nv_fb,
67 struct drm_mode_fb_cmd *mode_cmd, 69 struct drm_mode_fb_cmd2 *mode_cmd,
68 struct nouveau_bo *nvbo) 70 struct nouveau_bo *nvbo)
69{ 71{
70 struct drm_nouveau_private *dev_priv = dev->dev_private; 72 struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -107,14 +109,14 @@ nouveau_framebuffer_init(struct drm_device *dev,
107 109
108 if (!tile_flags) { 110 if (!tile_flags) {
109 if (dev_priv->card_type < NV_D0) 111 if (dev_priv->card_type < NV_D0)
110 nv_fb->r_pitch = 0x00100000 | fb->pitch; 112 nv_fb->r_pitch = 0x00100000 | fb->pitches[0];
111 else 113 else
112 nv_fb->r_pitch = 0x01000000 | fb->pitch; 114 nv_fb->r_pitch = 0x01000000 | fb->pitches[0];
113 } else { 115 } else {
114 u32 mode = nvbo->tile_mode; 116 u32 mode = nvbo->tile_mode;
115 if (dev_priv->card_type >= NV_C0) 117 if (dev_priv->card_type >= NV_C0)
116 mode >>= 4; 118 mode >>= 4;
117 nv_fb->r_pitch = ((fb->pitch / 4) << 4) | mode; 119 nv_fb->r_pitch = ((fb->pitches[0] / 4) << 4) | mode;
118 } 120 }
119 } 121 }
120 122
@@ -124,13 +126,13 @@ nouveau_framebuffer_init(struct drm_device *dev,
124static struct drm_framebuffer * 126static struct drm_framebuffer *
125nouveau_user_framebuffer_create(struct drm_device *dev, 127nouveau_user_framebuffer_create(struct drm_device *dev,
126 struct drm_file *file_priv, 128 struct drm_file *file_priv,
127 struct drm_mode_fb_cmd *mode_cmd) 129 struct drm_mode_fb_cmd2 *mode_cmd)
128{ 130{
129 struct nouveau_framebuffer *nouveau_fb; 131 struct nouveau_framebuffer *nouveau_fb;
130 struct drm_gem_object *gem; 132 struct drm_gem_object *gem;
131 int ret; 133 int ret;
132 134
133 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); 135 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
134 if (!gem) 136 if (!gem)
135 return ERR_PTR(-ENOENT); 137 return ERR_PTR(-ENOENT);
136 138
@@ -147,11 +149,186 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
147 return &nouveau_fb->base; 149 return &nouveau_fb->base;
148} 150}
149 151
150const struct drm_mode_config_funcs nouveau_mode_config_funcs = { 152static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
151 .fb_create = nouveau_user_framebuffer_create, 153 .fb_create = nouveau_user_framebuffer_create,
152 .output_poll_changed = nouveau_fbcon_output_poll_changed, 154 .output_poll_changed = nouveau_fbcon_output_poll_changed,
153}; 155};
154 156
157
158struct drm_prop_enum_list {
159 u8 gen_mask;
160 int type;
161 char *name;
162};
163
164static struct drm_prop_enum_list underscan[] = {
165 { 6, UNDERSCAN_AUTO, "auto" },
166 { 6, UNDERSCAN_OFF, "off" },
167 { 6, UNDERSCAN_ON, "on" },
168 {}
169};
170
171static struct drm_prop_enum_list dither_mode[] = {
172 { 7, DITHERING_MODE_AUTO, "auto" },
173 { 7, DITHERING_MODE_OFF, "off" },
174 { 1, DITHERING_MODE_ON, "on" },
175 { 6, DITHERING_MODE_STATIC2X2, "static 2x2" },
176 { 6, DITHERING_MODE_DYNAMIC2X2, "dynamic 2x2" },
177 { 4, DITHERING_MODE_TEMPORAL, "temporal" },
178 {}
179};
180
181static struct drm_prop_enum_list dither_depth[] = {
182 { 6, DITHERING_DEPTH_AUTO, "auto" },
183 { 6, DITHERING_DEPTH_6BPC, "6 bpc" },
184 { 6, DITHERING_DEPTH_8BPC, "8 bpc" },
185 {}
186};
187
188#define PROP_ENUM(p,gen,n,list) do { \
189 struct drm_prop_enum_list *l = (list); \
190 int c = 0; \
191 while (l->gen_mask) { \
192 if (l->gen_mask & (1 << (gen))) \
193 c++; \
194 l++; \
195 } \
196 if (c) { \
197 p = drm_property_create(dev, DRM_MODE_PROP_ENUM, n, c); \
198 l = (list); \
199 c = 0; \
200 while (p && l->gen_mask) { \
201 if (l->gen_mask & (1 << (gen))) { \
202 drm_property_add_enum(p, c, l->type, l->name); \
203 c++; \
204 } \
205 l++; \
206 } \
207 } \
208} while(0)
209
210int
211nouveau_display_init(struct drm_device *dev)
212{
213 struct drm_nouveau_private *dev_priv = dev->dev_private;
214 struct nouveau_display_engine *disp = &dev_priv->engine.display;
215 struct drm_connector *connector;
216 int ret;
217
218 ret = disp->init(dev);
219 if (ret)
220 return ret;
221
222 drm_kms_helper_poll_enable(dev);
223
224 /* enable hotplug interrupts */
225 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
226 struct nouveau_connector *conn = nouveau_connector(connector);
227 nouveau_gpio_irq(dev, 0, conn->hpd, 0xff, true);
228 }
229
230 return ret;
231}
232
233void
234nouveau_display_fini(struct drm_device *dev)
235{
236 struct drm_nouveau_private *dev_priv = dev->dev_private;
237 struct nouveau_display_engine *disp = &dev_priv->engine.display;
238 struct drm_connector *connector;
239
240 /* disable hotplug interrupts */
241 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
242 struct nouveau_connector *conn = nouveau_connector(connector);
243 nouveau_gpio_irq(dev, 0, conn->hpd, 0xff, false);
244 }
245
246 drm_kms_helper_poll_disable(dev);
247 disp->fini(dev);
248}
249
250int
251nouveau_display_create(struct drm_device *dev)
252{
253 struct drm_nouveau_private *dev_priv = dev->dev_private;
254 struct nouveau_display_engine *disp = &dev_priv->engine.display;
255 int ret, gen;
256
257 drm_mode_config_init(dev);
258 drm_mode_create_scaling_mode_property(dev);
259 drm_mode_create_dvi_i_properties(dev);
260
261 if (dev_priv->card_type < NV_50)
262 gen = 0;
263 else
264 if (dev_priv->card_type < NV_D0)
265 gen = 1;
266 else
267 gen = 2;
268
269 PROP_ENUM(disp->dithering_mode, gen, "dithering mode", dither_mode);
270 PROP_ENUM(disp->dithering_depth, gen, "dithering depth", dither_depth);
271 PROP_ENUM(disp->underscan_property, gen, "underscan", underscan);
272
273 disp->underscan_hborder_property =
274 drm_property_create(dev, DRM_MODE_PROP_RANGE,
275 "underscan hborder", 2);
276 disp->underscan_hborder_property->values[0] = 0;
277 disp->underscan_hborder_property->values[1] = 128;
278
279 disp->underscan_vborder_property =
280 drm_property_create(dev, DRM_MODE_PROP_RANGE,
281 "underscan vborder", 2);
282 disp->underscan_vborder_property->values[0] = 0;
283 disp->underscan_vborder_property->values[1] = 128;
284
285 dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
286 dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
287
288 dev->mode_config.min_width = 0;
289 dev->mode_config.min_height = 0;
290 if (dev_priv->card_type < NV_10) {
291 dev->mode_config.max_width = 2048;
292 dev->mode_config.max_height = 2048;
293 } else
294 if (dev_priv->card_type < NV_50) {
295 dev->mode_config.max_width = 4096;
296 dev->mode_config.max_height = 4096;
297 } else {
298 dev->mode_config.max_width = 8192;
299 dev->mode_config.max_height = 8192;
300 }
301
302 drm_kms_helper_poll_init(dev);
303 drm_kms_helper_poll_disable(dev);
304
305 ret = disp->create(dev);
306 if (ret)
307 return ret;
308
309 if (dev->mode_config.num_crtc) {
310 ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
311 if (ret)
312 return ret;
313 }
314
315 return ret;
316}
317
318void
319nouveau_display_destroy(struct drm_device *dev)
320{
321 struct drm_nouveau_private *dev_priv = dev->dev_private;
322 struct nouveau_display_engine *disp = &dev_priv->engine.display;
323
324 drm_vblank_cleanup(dev);
325
326 disp->destroy(dev);
327
328 drm_kms_helper_poll_fini(dev);
329 drm_mode_config_cleanup(dev);
330}
331
155int 332int
156nouveau_vblank_enable(struct drm_device *dev, int crtc) 333nouveau_vblank_enable(struct drm_device *dev, int crtc)
157{ 334{
@@ -294,7 +471,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
294 /* Initialize a page flip struct */ 471 /* Initialize a page flip struct */
295 *s = (struct nouveau_page_flip_state) 472 *s = (struct nouveau_page_flip_state)
296 { { }, event, nouveau_crtc(crtc)->index, 473 { { }, event, nouveau_crtc(crtc)->index,
297 fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y, 474 fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
298 new_bo->bo.offset }; 475 new_bo->bo.offset };
299 476
300 /* Choose the channel the flip will be handled in */ 477 /* Choose the channel the flip will be handled in */
@@ -305,7 +482,10 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
305 482
306 /* Emit a page flip */ 483 /* Emit a page flip */
307 if (dev_priv->card_type >= NV_50) { 484 if (dev_priv->card_type >= NV_50) {
308 ret = nv50_display_flip_next(crtc, fb, chan); 485 if (dev_priv->card_type >= NV_D0)
486 ret = nvd0_display_flip_next(crtc, fb, chan, 0);
487 else
488 ret = nv50_display_flip_next(crtc, fb, chan);
309 if (ret) { 489 if (ret) {
310 nouveau_channel_put(&chan); 490 nouveau_channel_put(&chan);
311 goto fail_unreserve; 491 goto fail_unreserve;