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 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_NVC0(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_NVC0(chan, NvSub2D, 0x0838, 2); 120 OUT_RING (chan, image->width); 121 OUT_RING (chan, image->height); 122 BEGIN_NVC0(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_NIC0(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 148nvc0_fbcon_accel_init(struct fb_info *info) 149{ 150 struct nouveau_fbdev *nfbdev = info->par; 151 struct drm_device *dev = nfbdev->dev; 152 struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; 153 struct nouveau_drm *drm = nouveau_drm(dev); 154 struct nouveau_channel *chan = drm->channel; 155 int ret, format; 156 157 ret = nvif_object_init(chan->object, NULL, 0x902d, 0x902d, NULL, 0, 158 &nfbdev->twod); 159 if (ret) 160 return ret; 161 162 switch (info->var.bits_per_pixel) { 163 case 8: 164 format = 0xf3; 165 break; 166 case 15: 167 format = 0xf8; 168 break; 169 case 16: 170 format = 0xe8; 171 break; 172 case 32: 173 switch (info->var.transp.length) { 174 case 0: /* depth 24 */ 175 case 8: /* depth 32, just use 24.. */ 176 format = 0xe6; 177 break; 178 case 2: /* depth 30 */ 179 format = 0xd1; 180 break; 181 default: 182 return -EINVAL; 183 } 184 break; 185 default: 186 return -EINVAL; 187 } 188 189 ret = RING_SPACE(chan, 60); 190 if (ret) { 191 WARN_ON(1); 192 nouveau_fbcon_gpu_lockup(info); 193 return ret; 194 } 195 196 BEGIN_NVC0(chan, NvSub2D, 0x0000, 1); 197 OUT_RING (chan, nfbdev->twod.handle); 198 BEGIN_NVC0(chan, NvSub2D, 0x0290, 1); 199 OUT_RING (chan, 0); 200 BEGIN_NVC0(chan, NvSub2D, 0x0888, 1); 201 OUT_RING (chan, 1); 202 BEGIN_NVC0(chan, NvSub2D, 0x02ac, 1); 203 OUT_RING (chan, 3); 204 BEGIN_NVC0(chan, NvSub2D, 0x02a0, 1); 205 OUT_RING (chan, 0x55); 206 BEGIN_NVC0(chan, NvSub2D, 0x08c0, 4); 207 OUT_RING (chan, 0); 208 OUT_RING (chan, 1); 209 OUT_RING (chan, 0); 210 OUT_RING (chan, 1); 211 BEGIN_NVC0(chan, NvSub2D, 0x0580, 2); 212 OUT_RING (chan, 4); 213 OUT_RING (chan, format); 214 BEGIN_NVC0(chan, NvSub2D, 0x02e8, 2); 215 OUT_RING (chan, 2); 216 OUT_RING (chan, 1); 217 218 BEGIN_NVC0(chan, NvSub2D, 0x0804, 1); 219 OUT_RING (chan, format); 220 BEGIN_NVC0(chan, NvSub2D, 0x0800, 1); 221 OUT_RING (chan, 1); 222 BEGIN_NVC0(chan, NvSub2D, 0x0808, 3); 223 OUT_RING (chan, 0); 224 OUT_RING (chan, 0); 225 OUT_RING (chan, 1); 226 BEGIN_NVC0(chan, NvSub2D, 0x081c, 1); 227 OUT_RING (chan, 1); 228 BEGIN_NVC0(chan, NvSub2D, 0x0840, 4); 229 OUT_RING (chan, 0); 230 OUT_RING (chan, 1); 231 OUT_RING (chan, 0); 232 OUT_RING (chan, 1); 233 BEGIN_NVC0(chan, NvSub2D, 0x0200, 10); 234 OUT_RING (chan, format); 235 OUT_RING (chan, 1); 236 OUT_RING (chan, 0); 237 OUT_RING (chan, 1); 238 OUT_RING (chan, 0); 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_NVC0(chan, NvSub2D, 0x0230, 10); 245 OUT_RING (chan, format); 246 OUT_RING (chan, 1); 247 OUT_RING (chan, 0); 248 OUT_RING (chan, 1); 249 OUT_RING (chan, 0); 250 OUT_RING (chan, info->fix.line_length); 251 OUT_RING (chan, info->var.xres_virtual); 252 OUT_RING (chan, info->var.yres_virtual); 253 OUT_RING (chan, upper_32_bits(fb->vma.offset)); 254 OUT_RING (chan, lower_32_bits(fb->vma.offset)); 255 FIRE_RING (chan); 256 257 return 0; 258} 259 260