linux/drivers/gpu/drm/nouveau/nv04_fbcon.c
<<
>>
Prefs
   1/*
   2 * Copyright 2009 Ben Skeggs
   3 * Copyright 2008 Stuart Bennett
   4 *
   5 * Permission is hereby granted, free of charge, to any person obtaining a
   6 * copy of this software and associated documentation files (the "Software"),
   7 * to deal in the Software without restriction, including without limitation
   8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   9 * and/or sell copies of the Software, and to permit persons to whom the
  10 * Software is furnished to do so, subject to the following conditions:
  11 *
  12 * The above copyright notice and this permission notice (including the next
  13 * paragraph) shall be included in all copies or substantial portions of the
  14 * Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22 * DEALINGS IN THE SOFTWARE.
  23 */
  24
  25#include "nouveau_drv.h"
  26#include "nouveau_dma.h"
  27#include "nouveau_fbcon.h"
  28
  29int
  30nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
  31{
  32        struct nouveau_fbdev *nfbdev = info->par;
  33        struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
  34        struct nouveau_channel *chan = drm->channel;
  35        int ret;
  36
  37        ret = RING_SPACE(chan, 4);
  38        if (ret)
  39                return ret;
  40
  41        BEGIN_NV04(chan, NvSubImageBlit, 0x0300, 3);
  42        OUT_RING(chan, (region->sy << 16) | region->sx);
  43        OUT_RING(chan, (region->dy << 16) | region->dx);
  44        OUT_RING(chan, (region->height << 16) | region->width);
  45        FIRE_RING(chan);
  46        return 0;
  47}
  48
  49int
  50nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  51{
  52        struct nouveau_fbdev *nfbdev = info->par;
  53        struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
  54        struct nouveau_channel *chan = drm->channel;
  55        int ret;
  56
  57        ret = RING_SPACE(chan, 7);
  58        if (ret)
  59                return ret;
  60
  61        BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
  62        OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3);
  63        BEGIN_NV04(chan, NvSubGdiRect, 0x03fc, 1);
  64        if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
  65            info->fix.visual == FB_VISUAL_DIRECTCOLOR)
  66                OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
  67        else
  68                OUT_RING(chan, rect->color);
  69        BEGIN_NV04(chan, NvSubGdiRect, 0x0400, 2);
  70        OUT_RING(chan, (rect->dx << 16) | rect->dy);
  71        OUT_RING(chan, (rect->width << 16) | rect->height);
  72        FIRE_RING(chan);
  73        return 0;
  74}
  75
  76int
  77nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
  78{
  79        struct nouveau_fbdev *nfbdev = info->par;
  80        struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
  81        struct nouveau_channel *chan = drm->channel;
  82        uint32_t fg;
  83        uint32_t bg;
  84        uint32_t dsize;
  85        uint32_t *data = (uint32_t *)image->data;
  86        int ret;
  87
  88        if (image->depth != 1)
  89                return -ENODEV;
  90
  91        ret = RING_SPACE(chan, 8);
  92        if (ret)
  93                return ret;
  94
  95        if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
  96            info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
  97                fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
  98                bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
  99        } else {
 100                fg = image->fg_color;
 101                bg = image->bg_color;
 102        }
 103
 104        BEGIN_NV04(chan, NvSubGdiRect, 0x0be4, 7);
 105        OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
 106        OUT_RING(chan, ((image->dy + image->height) << 16) |
 107                         ((image->dx + image->width) & 0xffff));
 108        OUT_RING(chan, bg);
 109        OUT_RING(chan, fg);
 110        OUT_RING(chan, (image->height << 16) | ALIGN(image->width, 8));
 111        OUT_RING(chan, (image->height << 16) | image->width);
 112        OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
 113
 114        dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
 115        while (dsize) {
 116                int iter_len = dsize > 128 ? 128 : dsize;
 117
 118                ret = RING_SPACE(chan, iter_len + 1);
 119                if (ret)
 120                        return ret;
 121
 122                BEGIN_NV04(chan, NvSubGdiRect, 0x0c00, iter_len);
 123                OUT_RINGp(chan, data, iter_len);
 124                data += iter_len;
 125                dsize -= iter_len;
 126        }
 127
 128        FIRE_RING(chan);
 129        return 0;
 130}
 131
 132int
 133nv04_fbcon_accel_init(struct fb_info *info)
 134{
 135        struct nouveau_fbdev *nfbdev = info->par;
 136        struct drm_device *dev = nfbdev->helper.dev;
 137        struct nouveau_drm *drm = nouveau_drm(dev);
 138        struct nouveau_channel *chan = drm->channel;
 139        struct nvif_device *device = &drm->client.device;
 140        int surface_fmt, pattern_fmt, rect_fmt;
 141        int ret;
 142
 143        switch (info->var.bits_per_pixel) {
 144        case 8:
 145                surface_fmt = 1;
 146                pattern_fmt = 3;
 147                rect_fmt = 3;
 148                break;
 149        case 16:
 150                surface_fmt = 4;
 151                pattern_fmt = 1;
 152                rect_fmt = 1;
 153                break;
 154        case 32:
 155                switch (info->var.transp.length) {
 156                case 0: /* depth 24 */
 157                case 8: /* depth 32 */
 158                        break;
 159                default:
 160                        return -EINVAL;
 161                }
 162
 163                surface_fmt = 6;
 164                pattern_fmt = 3;
 165                rect_fmt = 3;
 166                break;
 167        default:
 168                return -EINVAL;
 169        }
 170
 171        ret = nvif_object_init(&chan->user, 0x0062,
 172                               device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ?
 173                               0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d);
 174        if (ret)
 175                return ret;
 176
 177        ret = nvif_object_init(&chan->user, 0x0019, 0x0019, NULL, 0,
 178                               &nfbdev->clip);
 179        if (ret)
 180                return ret;
 181
 182        ret = nvif_object_init(&chan->user, 0x0043, 0x0043, NULL, 0,
 183                               &nfbdev->rop);
 184        if (ret)
 185                return ret;
 186
 187        ret = nvif_object_init(&chan->user, 0x0044, 0x0044, NULL, 0,
 188                               &nfbdev->patt);
 189        if (ret)
 190                return ret;
 191
 192        ret = nvif_object_init(&chan->user, 0x004a, 0x004a, NULL, 0,
 193                               &nfbdev->gdi);
 194        if (ret)
 195                return ret;
 196
 197        ret = nvif_object_init(&chan->user, 0x005f,
 198                               device->info.chipset >= 0x11 ? 0x009f : 0x005f,
 199                               NULL, 0, &nfbdev->blit);
 200        if (ret)
 201                return ret;
 202
 203        if (RING_SPACE(chan, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
 204                nouveau_fbcon_gpu_lockup(info);
 205                return 0;
 206        }
 207
 208        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 209        OUT_RING(chan, nfbdev->surf2d.handle);
 210        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0184, 2);
 211        OUT_RING(chan, chan->vram.handle);
 212        OUT_RING(chan, chan->vram.handle);
 213        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 4);
 214        OUT_RING(chan, surface_fmt);
 215        OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16));
 216        OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
 217        OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
 218
 219        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 220        OUT_RING(chan, nfbdev->rop.handle);
 221        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 1);
 222        OUT_RING(chan, 0x55);
 223
 224        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 225        OUT_RING(chan, nfbdev->patt.handle);
 226        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 8);
 227        OUT_RING(chan, pattern_fmt);
 228#ifdef __BIG_ENDIAN
 229        OUT_RING(chan, 2);
 230#else
 231        OUT_RING(chan, 1);
 232#endif
 233        OUT_RING(chan, 0);
 234        OUT_RING(chan, 1);
 235        OUT_RING(chan, ~0);
 236        OUT_RING(chan, ~0);
 237        OUT_RING(chan, ~0);
 238        OUT_RING(chan, ~0);
 239
 240        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 241        OUT_RING(chan, nfbdev->clip.handle);
 242        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 2);
 243        OUT_RING(chan, 0);
 244        OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual);
 245
 246        BEGIN_NV04(chan, NvSubImageBlit, 0x0000, 1);
 247        OUT_RING(chan, nfbdev->blit.handle);
 248        BEGIN_NV04(chan, NvSubImageBlit, 0x019c, 1);
 249        OUT_RING(chan, nfbdev->surf2d.handle);
 250        BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1);
 251        OUT_RING(chan, 3);
 252        if (device->info.chipset >= 0x11 /*XXX: oclass == 0x009f*/) {
 253                BEGIN_NV04(chan, NvSubImageBlit, 0x0120, 3);
 254                OUT_RING(chan, 0);
 255                OUT_RING(chan, 1);
 256                OUT_RING(chan, 2);
 257        }
 258
 259        BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1);
 260        OUT_RING(chan, nfbdev->gdi.handle);
 261        BEGIN_NV04(chan, NvSubGdiRect, 0x0198, 1);
 262        OUT_RING(chan, nfbdev->surf2d.handle);
 263        BEGIN_NV04(chan, NvSubGdiRect, 0x0188, 2);
 264        OUT_RING(chan, nfbdev->patt.handle);
 265        OUT_RING(chan, nfbdev->rop.handle);
 266        BEGIN_NV04(chan, NvSubGdiRect, 0x0304, 1);
 267        OUT_RING(chan, 1);
 268        BEGIN_NV04(chan, NvSubGdiRect, 0x0300, 1);
 269        OUT_RING(chan, rect_fmt);
 270        BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
 271        OUT_RING(chan, 3);
 272
 273        FIRE_RING(chan);
 274
 275        return 0;
 276}
 277
 278