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