aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_fbcon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_fbcon.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c189
1 files changed, 139 insertions, 50 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 02a4d1fd4845..a26d04740c88 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -49,6 +49,102 @@
49#include "nouveau_fbcon.h" 49#include "nouveau_fbcon.h"
50#include "nouveau_dma.h" 50#include "nouveau_dma.h"
51 51
52static void
53nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
54{
55 struct nouveau_fbdev *nfbdev = info->par;
56 struct drm_device *dev = nfbdev->dev;
57 struct drm_nouveau_private *dev_priv = dev->dev_private;
58 int ret;
59
60 if (info->state != FBINFO_STATE_RUNNING)
61 return;
62
63 ret = -ENODEV;
64 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
65 mutex_trylock(&dev_priv->channel->mutex)) {
66 if (dev_priv->card_type < NV_50)
67 ret = nv04_fbcon_fillrect(info, rect);
68 else
69 if (dev_priv->card_type < NV_C0)
70 ret = nv50_fbcon_fillrect(info, rect);
71 else
72 ret = nvc0_fbcon_fillrect(info, rect);
73 mutex_unlock(&dev_priv->channel->mutex);
74 }
75
76 if (ret == 0)
77 return;
78
79 if (ret != -ENODEV)
80 nouveau_fbcon_gpu_lockup(info);
81 cfb_fillrect(info, rect);
82}
83
84static void
85nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image)
86{
87 struct nouveau_fbdev *nfbdev = info->par;
88 struct drm_device *dev = nfbdev->dev;
89 struct drm_nouveau_private *dev_priv = dev->dev_private;
90 int ret;
91
92 if (info->state != FBINFO_STATE_RUNNING)
93 return;
94
95 ret = -ENODEV;
96 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
97 mutex_trylock(&dev_priv->channel->mutex)) {
98 if (dev_priv->card_type < NV_50)
99 ret = nv04_fbcon_copyarea(info, image);
100 else
101 if (dev_priv->card_type < NV_C0)
102 ret = nv50_fbcon_copyarea(info, image);
103 else
104 ret = nvc0_fbcon_copyarea(info, image);
105 mutex_unlock(&dev_priv->channel->mutex);
106 }
107
108 if (ret == 0)
109 return;
110
111 if (ret != -ENODEV)
112 nouveau_fbcon_gpu_lockup(info);
113 cfb_copyarea(info, image);
114}
115
116static void
117nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
118{
119 struct nouveau_fbdev *nfbdev = info->par;
120 struct drm_device *dev = nfbdev->dev;
121 struct drm_nouveau_private *dev_priv = dev->dev_private;
122 int ret;
123
124 if (info->state != FBINFO_STATE_RUNNING)
125 return;
126
127 ret = -ENODEV;
128 if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) &&
129 mutex_trylock(&dev_priv->channel->mutex)) {
130 if (dev_priv->card_type < NV_50)
131 ret = nv04_fbcon_imageblit(info, image);
132 else
133 if (dev_priv->card_type < NV_C0)
134 ret = nv50_fbcon_imageblit(info, image);
135 else
136 ret = nvc0_fbcon_imageblit(info, image);
137 mutex_unlock(&dev_priv->channel->mutex);
138 }
139
140 if (ret == 0)
141 return;
142
143 if (ret != -ENODEV)
144 nouveau_fbcon_gpu_lockup(info);
145 cfb_imageblit(info, image);
146}
147
52static int 148static int
53nouveau_fbcon_sync(struct fb_info *info) 149nouveau_fbcon_sync(struct fb_info *info)
54{ 150{
@@ -58,22 +154,36 @@ nouveau_fbcon_sync(struct fb_info *info)
58 struct nouveau_channel *chan = dev_priv->channel; 154 struct nouveau_channel *chan = dev_priv->channel;
59 int ret, i; 155 int ret, i;
60 156
61 if (!chan || !chan->accel_done || 157 if (!chan || !chan->accel_done || in_interrupt() ||
62 info->state != FBINFO_STATE_RUNNING || 158 info->state != FBINFO_STATE_RUNNING ||
63 info->flags & FBINFO_HWACCEL_DISABLED) 159 info->flags & FBINFO_HWACCEL_DISABLED)
64 return 0; 160 return 0;
65 161
66 if (RING_SPACE(chan, 4)) { 162 if (!mutex_trylock(&chan->mutex))
163 return 0;
164
165 ret = RING_SPACE(chan, 4);
166 if (ret) {
167 mutex_unlock(&chan->mutex);
67 nouveau_fbcon_gpu_lockup(info); 168 nouveau_fbcon_gpu_lockup(info);
68 return 0; 169 return 0;
69 } 170 }
70 171
71 BEGIN_RING(chan, 0, 0x0104, 1); 172 if (dev_priv->card_type >= NV_C0) {
72 OUT_RING(chan, 0); 173 BEGIN_NVC0(chan, 2, NvSub2D, 0x010c, 1);
73 BEGIN_RING(chan, 0, 0x0100, 1); 174 OUT_RING (chan, 0);
74 OUT_RING(chan, 0); 175 BEGIN_NVC0(chan, 2, NvSub2D, 0x0100, 1);
176 OUT_RING (chan, 0);
177 } else {
178 BEGIN_RING(chan, 0, 0x0104, 1);
179 OUT_RING (chan, 0);
180 BEGIN_RING(chan, 0, 0x0100, 1);
181 OUT_RING (chan, 0);
182 }
183
75 nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); 184 nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff);
76 FIRE_RING(chan); 185 FIRE_RING(chan);
186 mutex_unlock(&chan->mutex);
77 187
78 ret = -EBUSY; 188 ret = -EBUSY;
79 for (i = 0; i < 100000; i++) { 189 for (i = 0; i < 100000; i++) {
@@ -97,9 +207,9 @@ static struct fb_ops nouveau_fbcon_ops = {
97 .owner = THIS_MODULE, 207 .owner = THIS_MODULE,
98 .fb_check_var = drm_fb_helper_check_var, 208 .fb_check_var = drm_fb_helper_check_var,
99 .fb_set_par = drm_fb_helper_set_par, 209 .fb_set_par = drm_fb_helper_set_par,
100 .fb_fillrect = cfb_fillrect, 210 .fb_fillrect = nouveau_fbcon_fillrect,
101 .fb_copyarea = cfb_copyarea, 211 .fb_copyarea = nouveau_fbcon_copyarea,
102 .fb_imageblit = cfb_imageblit, 212 .fb_imageblit = nouveau_fbcon_imageblit,
103 .fb_sync = nouveau_fbcon_sync, 213 .fb_sync = nouveau_fbcon_sync,
104 .fb_pan_display = drm_fb_helper_pan_display, 214 .fb_pan_display = drm_fb_helper_pan_display,
105 .fb_blank = drm_fb_helper_blank, 215 .fb_blank = drm_fb_helper_blank,
@@ -108,29 +218,13 @@ static struct fb_ops nouveau_fbcon_ops = {
108 .fb_debug_leave = drm_fb_helper_debug_leave, 218 .fb_debug_leave = drm_fb_helper_debug_leave,
109}; 219};
110 220
111static struct fb_ops nv04_fbcon_ops = { 221static struct fb_ops nouveau_fbcon_sw_ops = {
112 .owner = THIS_MODULE, 222 .owner = THIS_MODULE,
113 .fb_check_var = drm_fb_helper_check_var, 223 .fb_check_var = drm_fb_helper_check_var,
114 .fb_set_par = drm_fb_helper_set_par, 224 .fb_set_par = drm_fb_helper_set_par,
115 .fb_fillrect = nv04_fbcon_fillrect, 225 .fb_fillrect = cfb_fillrect,
116 .fb_copyarea = nv04_fbcon_copyarea, 226 .fb_copyarea = cfb_copyarea,
117 .fb_imageblit = nv04_fbcon_imageblit, 227 .fb_imageblit = cfb_imageblit,
118 .fb_sync = nouveau_fbcon_sync,
119 .fb_pan_display = drm_fb_helper_pan_display,
120 .fb_blank = drm_fb_helper_blank,
121 .fb_setcmap = drm_fb_helper_setcmap,
122 .fb_debug_enter = drm_fb_helper_debug_enter,
123 .fb_debug_leave = drm_fb_helper_debug_leave,
124};
125
126static struct fb_ops nv50_fbcon_ops = {
127 .owner = THIS_MODULE,
128 .fb_check_var = drm_fb_helper_check_var,
129 .fb_set_par = drm_fb_helper_set_par,
130 .fb_fillrect = nv50_fbcon_fillrect,
131 .fb_copyarea = nv50_fbcon_copyarea,
132 .fb_imageblit = nv50_fbcon_imageblit,
133 .fb_sync = nouveau_fbcon_sync,
134 .fb_pan_display = drm_fb_helper_pan_display, 228 .fb_pan_display = drm_fb_helper_pan_display,
135 .fb_blank = drm_fb_helper_blank, 229 .fb_blank = drm_fb_helper_blank,
136 .fb_setcmap = drm_fb_helper_setcmap, 230 .fb_setcmap = drm_fb_helper_setcmap,
@@ -257,21 +351,16 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
257 FBINFO_HWACCEL_FILLRECT | 351 FBINFO_HWACCEL_FILLRECT |
258 FBINFO_HWACCEL_IMAGEBLIT; 352 FBINFO_HWACCEL_IMAGEBLIT;
259 info->flags |= FBINFO_CAN_FORCE_OUTPUT; 353 info->flags |= FBINFO_CAN_FORCE_OUTPUT;
260 info->fbops = &nouveau_fbcon_ops; 354 info->fbops = &nouveau_fbcon_sw_ops;
261 info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset - 355 info->fix.smem_start = dev->mode_config.fb_base +
262 dev_priv->vm_vram_base; 356 (nvbo->bo.mem.start << PAGE_SHIFT);
263 info->fix.smem_len = size; 357 info->fix.smem_len = size;
264 358
265 info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); 359 info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo);
266 info->screen_size = size; 360 info->screen_size = size;
267 361
268 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
269 drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); 362 drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
270 363
271 /* FIXME: we really shouldn't expose mmio space at all */
272 info->fix.mmio_start = pci_resource_start(pdev, 1);
273 info->fix.mmio_len = pci_resource_len(pdev, 1);
274
275 /* Set aperture base/size for vesafb takeover */ 364 /* Set aperture base/size for vesafb takeover */
276 info->apertures = dev_priv->apertures; 365 info->apertures = dev_priv->apertures;
277 if (!info->apertures) { 366 if (!info->apertures) {
@@ -285,19 +374,20 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
285 info->pixmap.flags = FB_PIXMAP_SYSTEM; 374 info->pixmap.flags = FB_PIXMAP_SYSTEM;
286 info->pixmap.scan_align = 1; 375 info->pixmap.scan_align = 1;
287 376
377 mutex_unlock(&dev->struct_mutex);
378
288 if (dev_priv->channel && !nouveau_nofbaccel) { 379 if (dev_priv->channel && !nouveau_nofbaccel) {
289 switch (dev_priv->card_type) { 380 ret = -ENODEV;
290 case NV_C0: 381 if (dev_priv->card_type < NV_50)
291 break; 382 ret = nv04_fbcon_accel_init(info);
292 case NV_50: 383 else
293 nv50_fbcon_accel_init(info); 384 if (dev_priv->card_type < NV_C0)
294 info->fbops = &nv50_fbcon_ops; 385 ret = nv50_fbcon_accel_init(info);
295 break; 386 else
296 default: 387 ret = nvc0_fbcon_accel_init(info);
297 nv04_fbcon_accel_init(info); 388
298 info->fbops = &nv04_fbcon_ops; 389 if (ret == 0)
299 break; 390 info->fbops = &nouveau_fbcon_ops;
300 };
301 } 391 }
302 392
303 nouveau_fbcon_zfill(dev, nfbdev); 393 nouveau_fbcon_zfill(dev, nfbdev);
@@ -308,7 +398,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
308 nouveau_fb->base.height, 398 nouveau_fb->base.height,
309 nvbo->bo.offset, nvbo); 399 nvbo->bo.offset, nvbo);
310 400
311 mutex_unlock(&dev->struct_mutex);
312 vga_switcheroo_client_fb_set(dev->pdev, info); 401 vga_switcheroo_client_fb_set(dev->pdev, info);
313 return 0; 402 return 0;
314 403