Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/nvc0: implement fbcon acceleration

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>

+300 -6
+3 -2
drivers/gpu/drm/nouveau/Makefile
··· 22 22 nv84_crypt.o \ 23 23 nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ 24 24 nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ 25 - nv50_cursor.o nv50_display.o nv50_fbcon.o \ 25 + nv50_cursor.o nv50_display.o \ 26 26 nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ 27 - nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ 27 + nv04_crtc.o nv04_display.o nv04_cursor.o \ 28 + nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \ 28 29 nv10_gpio.o nv50_gpio.o \ 29 30 nv50_calc.o \ 30 31 nv04_pm.o nv50_pm.o nva3_pm.o \
+20 -4
drivers/gpu/drm/nouveau/nouveau_fbcon.c
··· 68 68 else 69 69 if (dev_priv->card_type < NV_C0) 70 70 ret = nv50_fbcon_fillrect(info, rect); 71 + else 72 + ret = nvc0_fbcon_fillrect(info, rect); 71 73 mutex_unlock(&dev_priv->channel->mutex); 72 74 } 73 75 ··· 100 98 else 101 99 if (dev_priv->card_type < NV_C0) 102 100 ret = nv50_fbcon_copyarea(info, image); 101 + else 102 + ret = nvc0_fbcon_copyarea(info, image); 103 103 mutex_unlock(&dev_priv->channel->mutex); 104 104 } 105 105 ··· 132 128 else 133 129 if (dev_priv->card_type < NV_C0) 134 130 ret = nv50_fbcon_imageblit(info, image); 131 + else 132 + ret = nvc0_fbcon_imageblit(info, image); 135 133 mutex_unlock(&dev_priv->channel->mutex); 136 134 } 137 135 ··· 169 163 return 0; 170 164 } 171 165 172 - BEGIN_RING(chan, 0, 0x0104, 1); 173 - OUT_RING(chan, 0); 174 - BEGIN_RING(chan, 0, 0x0100, 1); 175 - OUT_RING(chan, 0); 166 + if (dev_priv->card_type >= NV_C0) { 167 + BEGIN_NVC0(chan, 2, NvSub2D, 0x010c, 1); 168 + OUT_RING (chan, 0); 169 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0100, 1); 170 + OUT_RING (chan, 0); 171 + } else { 172 + BEGIN_RING(chan, 0, 0x0104, 1); 173 + OUT_RING (chan, 0); 174 + BEGIN_RING(chan, 0, 0x0100, 1); 175 + OUT_RING (chan, 0); 176 + } 177 + 176 178 nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); 177 179 FIRE_RING(chan); 178 180 mutex_unlock(&chan->mutex); ··· 388 374 else 389 375 if (dev_priv->card_type < NV_C0) 390 376 ret = nv50_fbcon_accel_init(info); 377 + else 378 + ret = nvc0_fbcon_accel_init(info); 391 379 392 380 if (ret == 0) 393 381 info->fbops = &nouveau_fbcon_ops;
+6
drivers/gpu/drm/nouveau/nouveau_fbcon.h
··· 44 44 int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 45 45 int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); 46 46 int nv04_fbcon_accel_init(struct fb_info *info); 47 + 47 48 int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 48 49 int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); 49 50 int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); 50 51 int nv50_fbcon_accel_init(struct fb_info *info); 52 + 53 + int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 54 + int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); 55 + int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); 56 + int nvc0_fbcon_accel_init(struct fb_info *info); 51 57 52 58 void nouveau_fbcon_gpu_lockup(struct fb_info *info); 53 59
+271
drivers/gpu/drm/nouveau/nvc0_fbcon.c
··· 1 + /* 2 + * Copyright 2010 Red Hat Inc. 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 + * OTHER DEALINGS IN THE SOFTWARE. 21 + * 22 + * Authors: Ben Skeggs 23 + */ 24 + 25 + #include "drmP.h" 26 + #include "nouveau_drv.h" 27 + #include "nouveau_dma.h" 28 + #include "nouveau_ramht.h" 29 + #include "nouveau_fbcon.h" 30 + #include "nouveau_mm.h" 31 + 32 + int 33 + nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 34 + { 35 + struct nouveau_fbdev *nfbdev = info->par; 36 + struct drm_device *dev = nfbdev->dev; 37 + struct drm_nouveau_private *dev_priv = dev->dev_private; 38 + struct nouveau_channel *chan = dev_priv->channel; 39 + int ret; 40 + 41 + ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11); 42 + if (ret) 43 + return ret; 44 + 45 + if (rect->rop != ROP_COPY) { 46 + BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); 47 + OUT_RING (chan, 1); 48 + } 49 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0588, 1); 50 + if (info->fix.visual == FB_VISUAL_TRUECOLOR || 51 + info->fix.visual == FB_VISUAL_DIRECTCOLOR) 52 + OUT_RING (chan, ((uint32_t *)info->pseudo_palette)[rect->color]); 53 + else 54 + OUT_RING (chan, rect->color); 55 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0600, 4); 56 + OUT_RING (chan, rect->dx); 57 + OUT_RING (chan, rect->dy); 58 + OUT_RING (chan, rect->dx + rect->width); 59 + OUT_RING (chan, rect->dy + rect->height); 60 + if (rect->rop != ROP_COPY) { 61 + BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); 62 + OUT_RING (chan, 3); 63 + } 64 + FIRE_RING(chan); 65 + return 0; 66 + } 67 + 68 + int 69 + nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) 70 + { 71 + struct nouveau_fbdev *nfbdev = info->par; 72 + struct drm_device *dev = nfbdev->dev; 73 + struct drm_nouveau_private *dev_priv = dev->dev_private; 74 + struct nouveau_channel *chan = dev_priv->channel; 75 + int ret; 76 + 77 + ret = RING_SPACE(chan, 12); 78 + if (ret) 79 + return ret; 80 + 81 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0110, 1); 82 + OUT_RING (chan, 0); 83 + BEGIN_NVC0(chan, 2, NvSub2D, 0x08b0, 4); 84 + OUT_RING (chan, region->dx); 85 + OUT_RING (chan, region->dy); 86 + OUT_RING (chan, region->width); 87 + OUT_RING (chan, region->height); 88 + BEGIN_NVC0(chan, 2, NvSub2D, 0x08d0, 4); 89 + OUT_RING (chan, 0); 90 + OUT_RING (chan, region->sx); 91 + OUT_RING (chan, 0); 92 + OUT_RING (chan, region->sy); 93 + FIRE_RING(chan); 94 + return 0; 95 + } 96 + 97 + int 98 + nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) 99 + { 100 + struct nouveau_fbdev *nfbdev = info->par; 101 + struct drm_device *dev = nfbdev->dev; 102 + struct drm_nouveau_private *dev_priv = dev->dev_private; 103 + struct nouveau_channel *chan = dev_priv->channel; 104 + uint32_t width, dwords, *data = (uint32_t *)image->data; 105 + uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); 106 + uint32_t *palette = info->pseudo_palette; 107 + int ret; 108 + 109 + if (image->depth != 1) 110 + return -ENODEV; 111 + 112 + ret = RING_SPACE(chan, 11); 113 + if (ret) 114 + return ret; 115 + 116 + width = ALIGN(image->width, 32); 117 + dwords = (width * image->height) >> 5; 118 + 119 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0814, 2); 120 + if (info->fix.visual == FB_VISUAL_TRUECOLOR || 121 + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 122 + OUT_RING (chan, palette[image->bg_color] | mask); 123 + OUT_RING (chan, palette[image->fg_color] | mask); 124 + } else { 125 + OUT_RING (chan, image->bg_color); 126 + OUT_RING (chan, image->fg_color); 127 + } 128 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0838, 2); 129 + OUT_RING (chan, image->width); 130 + OUT_RING (chan, image->height); 131 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0850, 4); 132 + OUT_RING (chan, 0); 133 + OUT_RING (chan, image->dx); 134 + OUT_RING (chan, 0); 135 + OUT_RING (chan, image->dy); 136 + 137 + while (dwords) { 138 + int push = dwords > 2047 ? 2047 : dwords; 139 + 140 + ret = RING_SPACE(chan, push + 1); 141 + if (ret) 142 + return ret; 143 + 144 + dwords -= push; 145 + 146 + BEGIN_NVC0(chan, 6, NvSub2D, 0x0860, push); 147 + OUT_RINGp(chan, data, push); 148 + data += push; 149 + } 150 + 151 + FIRE_RING(chan); 152 + return 0; 153 + } 154 + 155 + int 156 + nvc0_fbcon_accel_init(struct fb_info *info) 157 + { 158 + struct nouveau_fbdev *nfbdev = info->par; 159 + struct drm_device *dev = nfbdev->dev; 160 + struct drm_nouveau_private *dev_priv = dev->dev_private; 161 + struct nouveau_channel *chan = dev_priv->channel; 162 + struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo; 163 + int ret, format; 164 + 165 + ret = nouveau_gpuobj_gr_new(chan, 0x902d, 0x902d); 166 + if (ret) 167 + return ret; 168 + 169 + switch (info->var.bits_per_pixel) { 170 + case 8: 171 + format = 0xf3; 172 + break; 173 + case 15: 174 + format = 0xf8; 175 + break; 176 + case 16: 177 + format = 0xe8; 178 + break; 179 + case 32: 180 + switch (info->var.transp.length) { 181 + case 0: /* depth 24 */ 182 + case 8: /* depth 32, just use 24.. */ 183 + format = 0xe6; 184 + break; 185 + case 2: /* depth 30 */ 186 + format = 0xd1; 187 + break; 188 + default: 189 + return -EINVAL; 190 + } 191 + break; 192 + default: 193 + return -EINVAL; 194 + } 195 + 196 + ret = RING_SPACE(chan, 60); 197 + if (ret) { 198 + WARN_ON(1); 199 + nouveau_fbcon_gpu_lockup(info); 200 + return ret; 201 + } 202 + 203 + printk(KERN_ERR "fb vma 0x%010llx\n", nvbo->vma.offset); 204 + 205 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0000, 1); 206 + OUT_RING (chan, 0x0000902d); 207 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0104, 2); 208 + OUT_RING (chan, upper_32_bits(chan->notifier_bo->bo.offset)); 209 + OUT_RING (chan, lower_32_bits(chan->notifier_bo->bo.offset)); 210 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0290, 1); 211 + OUT_RING (chan, 0); 212 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0888, 1); 213 + OUT_RING (chan, 1); 214 + BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); 215 + OUT_RING (chan, 3); 216 + BEGIN_NVC0(chan, 2, NvSub2D, 0x02a0, 1); 217 + OUT_RING (chan, 0x55); 218 + BEGIN_NVC0(chan, 2, NvSub2D, 0x08c0, 4); 219 + OUT_RING (chan, 0); 220 + OUT_RING (chan, 1); 221 + OUT_RING (chan, 0); 222 + OUT_RING (chan, 1); 223 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0580, 2); 224 + OUT_RING (chan, 4); 225 + OUT_RING (chan, format); 226 + BEGIN_NVC0(chan, 2, NvSub2D, 0x02e8, 2); 227 + OUT_RING (chan, 2); 228 + OUT_RING (chan, 1); 229 + 230 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0804, 1); 231 + OUT_RING (chan, format); 232 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0800, 1); 233 + OUT_RING (chan, 1); 234 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0808, 3); 235 + OUT_RING (chan, 0); 236 + OUT_RING (chan, 0); 237 + OUT_RING (chan, 1); 238 + BEGIN_NVC0(chan, 2, NvSub2D, 0x081c, 1); 239 + OUT_RING (chan, 1); 240 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0840, 4); 241 + OUT_RING (chan, 0); 242 + OUT_RING (chan, 1); 243 + OUT_RING (chan, 0); 244 + OUT_RING (chan, 1); 245 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0200, 10); 246 + OUT_RING (chan, format); 247 + OUT_RING (chan, 1); 248 + OUT_RING (chan, 0); 249 + OUT_RING (chan, 1); 250 + OUT_RING (chan, 0); 251 + OUT_RING (chan, info->fix.line_length); 252 + OUT_RING (chan, info->var.xres_virtual); 253 + OUT_RING (chan, info->var.yres_virtual); 254 + OUT_RING (chan, upper_32_bits(nvbo->vma.offset)); 255 + OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); 256 + BEGIN_NVC0(chan, 2, NvSub2D, 0x0230, 10); 257 + OUT_RING (chan, format); 258 + OUT_RING (chan, 1); 259 + OUT_RING (chan, 0); 260 + OUT_RING (chan, 1); 261 + OUT_RING (chan, 0); 262 + OUT_RING (chan, info->fix.line_length); 263 + OUT_RING (chan, info->var.xres_virtual); 264 + OUT_RING (chan, info->var.yres_virtual); 265 + OUT_RING (chan, upper_32_bits(nvbo->vma.offset)); 266 + OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); 267 + FIRE_RING (chan); 268 + 269 + return 0; 270 + } 271 +