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 30nvc0_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_NVC0(chan, NvSub2D, 0x02ac, 1); 43 OUT_RING (chan, 1); 44 } 45 BEGIN_NVC0(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_NVC0(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_NVC0(chan, NvSub2D, 0x02ac, 1); 58 OUT_RING (chan, 3); 59 } 60 FIRE_RING(chan); 61 return 0; 62} 63 64int 65nvc0_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_NVC0(chan, NvSub2D, 0x0110, 1); 77 OUT_RING (chan, 0); 78 BEGIN_NVC0(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_NVC0(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 93nvc0_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 width, 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 width = ALIGN(image->width, 32); 111 dwords = (width * image->height) >> 5; 112 113 BEGIN_NVC0(chan, NvSub2D, 0x0814, 2); 114 if (info->fix.visual == FB_VISUAL_TRUECOLOR || 115 info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 116 OUT_RING (chan, palette[image->bg_color] | mask); 117 OUT_RING (chan, palette[image->fg_color] | mask); 118 } else { 119 OUT_RING (chan, image->bg_color); 120 OUT_RING (chan, image->fg_color); 121 } 122 BEGIN_NVC0(chan, NvSub2D, 0x0838, 2); 123 OUT_RING (chan, image->width); 124 OUT_RING (chan, image->height); 125 BEGIN_NVC0(chan, NvSub2D, 0x0850, 4); 126 OUT_RING (chan, 0); 127 OUT_RING (chan, image->dx); 128 OUT_RING (chan, 0); 129 OUT_RING (chan, image->dy); 130 131 while (dwords) { 132 int push = dwords > 2047 ? 2047 : dwords; 133 134 ret = RING_SPACE(chan, push + 1); 135 if (ret) 136 return ret; 137 138 dwords -= push; 139 140 BEGIN_NIC0(chan, NvSub2D, 0x0860, push); 141 OUT_RINGp(chan, data, push); 142 data += push; 143 } 144 145 FIRE_RING(chan); 146 return 0; 147} 148 149int 150nvc0_fbcon_accel_init(struct fb_info *info) 151{ 152 struct nouveau_fbdev *nfbdev = info->par; 153 struct drm_device *dev = nfbdev->dev; 154 struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; 155 struct nouveau_drm *drm = nouveau_drm(dev); 156 struct nouveau_channel *chan = drm->channel; 157 int ret, format; 158 159 ret = nvif_object_init(&chan->user, 0x902d, 0x902d, NULL, 0, 160 &nfbdev->twod); 161 if (ret) 162 return ret; 163 164 switch (info->var.bits_per_pixel) { 165 case 8: 166 format = 0xf3; 167 break; 168 case 15: 169 format = 0xf8; 170 break; 171 case 16: 172 format = 0xe8; 173 break; 174 case 32: 175 switch (info->var.transp.length) { 176 case 0: /* depth 24 */ 177 case 8: /* depth 32, just use 24.. */ 178 format = 0xe6; 179 break; 180 case 2: /* depth 30 */ 181 format = 0xd1; 182 break; 183 default: 184 return -EINVAL; 185 } 186 break; 187 default: 188 return -EINVAL; 189 } 190 191 ret = RING_SPACE(chan, 58); 192 if (ret) { 193 WARN_ON(1); 194 nouveau_fbcon_gpu_lockup(info); 195 return ret; 196 } 197 198 BEGIN_NVC0(chan, NvSub2D, 0x0000, 1); 199 OUT_RING (chan, nfbdev->twod.handle); 200 BEGIN_NVC0(chan, NvSub2D, 0x0290, 1); 201 OUT_RING (chan, 0); 202 BEGIN_NVC0(chan, NvSub2D, 0x0888, 1); 203 OUT_RING (chan, 1); 204 BEGIN_NVC0(chan, NvSub2D, 0x02ac, 1); 205 OUT_RING (chan, 3); 206 BEGIN_NVC0(chan, NvSub2D, 0x02a0, 1); 207 OUT_RING (chan, 0x55); 208 BEGIN_NVC0(chan, NvSub2D, 0x08c0, 4); 209 OUT_RING (chan, 0); 210 OUT_RING (chan, 1); 211 OUT_RING (chan, 0); 212 OUT_RING (chan, 1); 213 BEGIN_NVC0(chan, NvSub2D, 0x0580, 2); 214 OUT_RING (chan, 4); 215 OUT_RING (chan, format); 216 BEGIN_NVC0(chan, NvSub2D, 0x02e8, 2); 217 OUT_RING (chan, 2); 218 OUT_RING (chan, 1); 219 220 BEGIN_NVC0(chan, NvSub2D, 0x0804, 1); 221 OUT_RING (chan, format); 222 BEGIN_NVC0(chan, NvSub2D, 0x0800, 1); 223 OUT_RING (chan, 1); 224 BEGIN_NVC0(chan, NvSub2D, 0x0808, 3); 225 OUT_RING (chan, 0); 226 OUT_RING (chan, 0); 227 OUT_RING (chan, 1); 228 BEGIN_NVC0(chan, NvSub2D, 0x081c, 1); 229 OUT_RING (chan, 1); 230 BEGIN_NVC0(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_NVC0(chan, NvSub2D, 0x0200, 10); 236 OUT_RING (chan, format); 237 OUT_RING (chan, 1); 238 OUT_RING (chan, 0); 239 OUT_RING (chan, 1); 240 OUT_RING (chan, 0); 241 OUT_RING (chan, info->fix.line_length); 242 OUT_RING (chan, info->var.xres_virtual); 243 OUT_RING (chan, info->var.yres_virtual); 244 OUT_RING (chan, upper_32_bits(fb->vma.offset)); 245 OUT_RING (chan, lower_32_bits(fb->vma.offset)); 246 BEGIN_NVC0(chan, NvSub2D, 0x0230, 10); 247 OUT_RING (chan, format); 248 OUT_RING (chan, 1); 249 OUT_RING (chan, 0); 250 OUT_RING (chan, 1); 251 OUT_RING (chan, 0); 252 OUT_RING (chan, info->fix.line_length); 253 OUT_RING (chan, info->var.xres_virtual); 254 OUT_RING (chan, info->var.yres_virtual); 255 OUT_RING (chan, upper_32_bits(fb->vma.offset)); 256 OUT_RING (chan, lower_32_bits(fb->vma.offset)); 257 FIRE_RING (chan); 258 259 return 0; 260} 261 262