1#include "drmP.h" 2#include "nouveau_drv.h" 3#include "nouveau_dma.h" 4#include "nouveau_fbcon.h" 5 6void 7nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 8{ 9 struct nouveau_fbdev *nfbdev = info->par; 10 struct drm_device *dev = nfbdev->dev; 11 struct drm_nouveau_private *dev_priv = dev->dev_private; 12 struct nouveau_channel *chan = dev_priv->channel; 13 14 if (info->state != FBINFO_STATE_RUNNING) 15 return; 16 17 if (!(info->flags & FBINFO_HWACCEL_DISABLED) && 18 RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) { 19 nouveau_fbcon_gpu_lockup(info); 20 } 21 22 if (info->flags & FBINFO_HWACCEL_DISABLED) { 23 cfb_fillrect(info, rect); 24 return; 25 } 26 27 if (rect->rop != ROP_COPY) { 28 BEGIN_RING(chan, NvSub2D, 0x02ac, 1); 29 OUT_RING(chan, 1); 30 } 31 BEGIN_RING(chan, NvSub2D, 0x0588, 1); 32 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 33 info->fix.visual == FB_VISUAL_DIRECTCOLOR) 34 OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]); 35 else 36 OUT_RING(chan, rect->color); 37 BEGIN_RING(chan, NvSub2D, 0x0600, 4); 38 OUT_RING(chan, rect->dx); 39 OUT_RING(chan, rect->dy); 40 OUT_RING(chan, rect->dx + rect->width); 41 OUT_RING(chan, rect->dy + rect->height); 42 if (rect->rop != ROP_COPY) { 43 BEGIN_RING(chan, NvSub2D, 0x02ac, 1); 44 OUT_RING(chan, 3); 45 } 46 FIRE_RING(chan); 47} 48 49void 50nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) 51{ 52 struct nouveau_fbdev *nfbdev = info->par; 53 struct drm_device *dev = nfbdev->dev; 54 struct drm_nouveau_private *dev_priv = dev->dev_private; 55 struct nouveau_channel *chan = dev_priv->channel; 56 57 if (info->state != FBINFO_STATE_RUNNING) 58 return; 59 60 if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) { 61 nouveau_fbcon_gpu_lockup(info); 62 } 63 64 if (info->flags & FBINFO_HWACCEL_DISABLED) { 65 cfb_copyarea(info, region); 66 return; 67 } 68 69 BEGIN_RING(chan, NvSub2D, 0x0110, 1); 70 OUT_RING(chan, 0); 71 BEGIN_RING(chan, NvSub2D, 0x08b0, 4); 72 OUT_RING(chan, region->dx); 73 OUT_RING(chan, region->dy); 74 OUT_RING(chan, region->width); 75 OUT_RING(chan, region->height); 76 BEGIN_RING(chan, NvSub2D, 0x08d0, 4); 77 OUT_RING(chan, 0); 78 OUT_RING(chan, region->sx); 79 OUT_RING(chan, 0); 80 OUT_RING(chan, region->sy); 81 FIRE_RING(chan); 82} 83 84void 85nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *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 struct nouveau_channel *chan = dev_priv->channel; 91 uint32_t width, dwords, *data = (uint32_t *)image->data; 92 uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); 93 uint32_t *palette = info->pseudo_palette; 94 95 if (info->state != FBINFO_STATE_RUNNING) 96 return; 97 98 if (image->depth != 1) { 99 cfb_imageblit(info, image); 100 return; 101 } 102 103 if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) { 104 nouveau_fbcon_gpu_lockup(info); 105 } 106 107 if (info->flags & FBINFO_HWACCEL_DISABLED) { 108 cfb_imageblit(info, image); 109 return; 110 } 111 112 width = ALIGN(image->width, 32); 113 dwords = (width * image->height) >> 5; 114 115 BEGIN_RING(chan, NvSub2D, 0x0814, 2); 116 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 117 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 118 OUT_RING(chan, palette[image->bg_color] | mask); 119 OUT_RING(chan, palette[image->fg_color] | mask); 120 } else { 121 OUT_RING(chan, image->bg_color); 122 OUT_RING(chan, image->fg_color); 123 } 124 BEGIN_RING(chan, NvSub2D, 0x0838, 2); 125 OUT_RING(chan, image->width); 126 OUT_RING(chan, image->height); 127 BEGIN_RING(chan, NvSub2D, 0x0850, 4); 128 OUT_RING(chan, 0); 129 OUT_RING(chan, image->dx); 130 OUT_RING(chan, 0); 131 OUT_RING(chan, image->dy); 132 133 while (dwords) { 134 int push = dwords > 2047 ? 2047 : dwords; 135 136 if (RING_SPACE(chan, push + 1)) { 137 nouveau_fbcon_gpu_lockup(info); 138 cfb_imageblit(info, image); 139 return; 140 } 141 142 dwords -= push; 143 144 BEGIN_RING(chan, NvSub2D, 0x40000860, push); 145 OUT_RINGp(chan, data, push); 146 data += push; 147 } 148 149 FIRE_RING(chan); 150} 151 152int 153nv50_fbcon_accel_init(struct fb_info *info) 154{ 155 struct nouveau_fbdev *nfbdev = info->par; 156 struct drm_device *dev = nfbdev->dev; 157 struct drm_nouveau_private *dev_priv = dev->dev_private; 158 struct nouveau_channel *chan = dev_priv->channel; 159 struct nouveau_gpuobj *eng2d = NULL; 160 uint64_t fb; 161 int ret, format; 162 163 fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base; 164 165 switch (info->var.bits_per_pixel) { 166 case 8: 167 format = 0xf3; 168 break; 169 case 15: 170 format = 0xf8; 171 break; 172 case 16: 173 format = 0xe8; 174 break; 175 case 32: 176 switch (info->var.transp.length) { 177 case 0: /* depth 24 */ 178 case 8: /* depth 32, just use 24.. */ 179 format = 0xe6; 180 break; 181 case 2: /* depth 30 */ 182 format = 0xd1; 183 break; 184 default: 185 return -EINVAL; 186 } 187 break; 188 default: 189 return -EINVAL; 190 } 191 192 ret = nouveau_gpuobj_gr_new(dev_priv->channel, 0x502d, &eng2d); 193 if (ret) 194 return ret; 195 196 ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL); 197 if (ret) 198 return ret; 199 200 ret = RING_SPACE(chan, 59); 201 if (ret) { 202 nouveau_fbcon_gpu_lockup(info); 203 return ret; 204 } 205 206 BEGIN_RING(chan, NvSub2D, 0x0000, 1); 207 OUT_RING(chan, Nv2D); 208 BEGIN_RING(chan, NvSub2D, 0x0180, 4); 209 OUT_RING(chan, NvNotify0); 210 OUT_RING(chan, chan->vram_handle); 211 OUT_RING(chan, chan->vram_handle); 212 OUT_RING(chan, chan->vram_handle); 213 BEGIN_RING(chan, NvSub2D, 0x0290, 1); 214 OUT_RING(chan, 0); 215 BEGIN_RING(chan, NvSub2D, 0x0888, 1); 216 OUT_RING(chan, 1); 217 BEGIN_RING(chan, NvSub2D, 0x02ac, 1); 218 OUT_RING(chan, 3); 219 BEGIN_RING(chan, NvSub2D, 0x02a0, 1); 220 OUT_RING(chan, 0x55); 221 BEGIN_RING(chan, NvSub2D, 0x08c0, 4); 222 OUT_RING(chan, 0); 223 OUT_RING(chan, 1); 224 OUT_RING(chan, 0); 225 OUT_RING(chan, 1); 226 BEGIN_RING(chan, NvSub2D, 0x0580, 2); 227 OUT_RING(chan, 4); 228 OUT_RING(chan, format); 229 BEGIN_RING(chan, NvSub2D, 0x02e8, 2); 230 OUT_RING(chan, 2); 231 OUT_RING(chan, 1); 232 BEGIN_RING(chan, NvSub2D, 0x0804, 1); 233 OUT_RING(chan, format); 234 BEGIN_RING(chan, NvSub2D, 0x0800, 1); 235 OUT_RING(chan, 1); 236 BEGIN_RING(chan, NvSub2D, 0x0808, 3); 237 OUT_RING(chan, 0); 238 OUT_RING(chan, 0); 239 OUT_RING(chan, 1); 240 BEGIN_RING(chan, NvSub2D, 0x081c, 1); 241 OUT_RING(chan, 1); 242 BEGIN_RING(chan, NvSub2D, 0x0840, 4); 243 OUT_RING(chan, 0); 244 OUT_RING(chan, 1); 245 OUT_RING(chan, 0); 246 OUT_RING(chan, 1); 247 BEGIN_RING(chan, NvSub2D, 0x0200, 2); 248 OUT_RING(chan, format); 249 OUT_RING(chan, 1); 250 BEGIN_RING(chan, NvSub2D, 0x0214, 5); 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(fb)); 255 OUT_RING(chan, lower_32_bits(fb)); 256 BEGIN_RING(chan, NvSub2D, 0x0230, 2); 257 OUT_RING(chan, format); 258 OUT_RING(chan, 1); 259 BEGIN_RING(chan, NvSub2D, 0x0244, 5); 260 OUT_RING(chan, info->fix.line_length); 261 OUT_RING(chan, info->var.xres_virtual); 262 OUT_RING(chan, info->var.yres_virtual); 263 OUT_RING(chan, upper_32_bits(fb)); 264 OUT_RING(chan, lower_32_bits(fb)); 265 266 return 0; 267} 268