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 <core/object.h>
  26
  27#include "nouveau_drm.h"
  28#include "nouveau_dma.h"
  29#include "nouveau_fbcon.h"
  30
  31int
  32nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
  33{
  34        struct nouveau_fbdev *nfbdev = info->par;
  35        struct nouveau_drm *drm = nouveau_drm(nfbdev->dev);
  36        struct nouveau_channel *chan = drm->channel;
  37        int ret;
  38
  39        ret = RING_SPACE(chan, 4);
  40        if (ret)
  41                return ret;
  42
  43        BEGIN_NV04(chan, NvSubImageBlit, 0x0300, 3);
  44        OUT_RING(chan, (region->sy << 16) | region->sx);
  45        OUT_RING(chan, (region->dy << 16) | region->dx);
  46        OUT_RING(chan, (region->height << 16) | region->width);
  47        FIRE_RING(chan);
  48        return 0;
  49}
  50
  51int
  52nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  53{
  54        struct nouveau_fbdev *nfbdev = info->par;
  55        struct nouveau_drm *drm = nouveau_drm(nfbdev->dev);
  56        struct nouveau_channel *chan = drm->channel;
  57        int ret;
  58
  59        ret = RING_SPACE(chan, 7);
  60        if (ret)
  61                return ret;
  62
  63        BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
  64        OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3);
  65        BEGIN_NV04(chan, NvSubGdiRect, 0x03fc, 1);
  66        if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
  67            info->fix.visual == FB_VISUAL_DIRECTCOLOR)
  68                OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
  69        else
  70                OUT_RING(chan, rect->color);
  71        BEGIN_NV04(chan, NvSubGdiRect, 0x0400, 2);
  72        OUT_RING(chan, (rect->dx << 16) | rect->dy);
  73        OUT_RING(chan, (rect->width << 16) | rect->height);
  74        FIRE_RING(chan);
  75        return 0;
  76}
  77
  78int
  79nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
  80{
  81        struct nouveau_fbdev *nfbdev = info->par;
  82        struct nouveau_drm *drm = nouveau_drm(nfbdev->dev);
  83        struct nouveau_channel *chan = drm->channel;
  84        uint32_t fg;
  85        uint32_t bg;
  86        uint32_t dsize;
  87        uint32_t width;
  88        uint32_t *data = (uint32_t *)image->data;
  89        int ret;
  90
  91        if (image->depth != 1)
  92                return -ENODEV;
  93
  94        ret = RING_SPACE(chan, 8);
  95        if (ret)
  96                return ret;
  97
  98        width = ALIGN(image->width, 8);
  99        dsize = ALIGN(width * image->height, 32) >> 5;
 100
 101        if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
 102            info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
 103                fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
 104                bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
 105        } else {
 106                fg = image->fg_color;
 107                bg = image->bg_color;
 108        }
 109
 110        BEGIN_NV04(chan, NvSubGdiRect, 0x0be4, 7);
 111        OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
 112        OUT_RING(chan, ((image->dy + image->height) << 16) |
 113                         ((image->dx + image->width) & 0xffff));
 114        OUT_RING(chan, bg);
 115        OUT_RING(chan, fg);
 116        OUT_RING(chan, (image->height << 16) | width);
 117        OUT_RING(chan, (image->height << 16) | image->width);
 118        OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
 119
 120        while (dsize) {
 121                int iter_len = dsize > 128 ? 128 : dsize;
 122
 123                ret = RING_SPACE(chan, iter_len + 1);
 124                if (ret)
 125                        return ret;
 126
 127                BEGIN_NV04(chan, NvSubGdiRect, 0x0c00, iter_len);
 128                OUT_RINGp(chan, data, iter_len);
 129                data += iter_len;
 130                dsize -= iter_len;
 131        }
 132
 133        FIRE_RING(chan);
 134        return 0;
 135}
 136
 137int
 138nv04_fbcon_accel_init(struct fb_info *info)
 139{
 140        struct nouveau_fbdev *nfbdev = info->par;
 141        struct drm_device *dev = nfbdev->dev;
 142        struct nouveau_drm *drm = nouveau_drm(dev);
 143        struct nouveau_channel *chan = drm->channel;
 144        struct nouveau_device *device = nv_device(drm->device);
 145        struct nouveau_object *object;
 146        int surface_fmt, pattern_fmt, rect_fmt;
 147        int ret;
 148
 149        switch (info->var.bits_per_pixel) {
 150        case 8:
 151                surface_fmt = 1;
 152                pattern_fmt = 3;
 153                rect_fmt = 3;
 154                break;
 155        case 16:
 156                surface_fmt = 4;
 157                pattern_fmt = 1;
 158                rect_fmt = 1;
 159                break;
 160        case 32:
 161                switch (info->var.transp.length) {
 162                case 0: /* depth 24 */
 163                case 8: /* depth 32 */
 164                        break;
 165                default:
 166                        return -EINVAL;
 167                }
 168
 169                surface_fmt = 6;
 170                pattern_fmt = 3;
 171                rect_fmt = 3;
 172                break;
 173        default:
 174                return -EINVAL;
 175        }
 176
 177        ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvCtxSurf2D,
 178                                 device->card_type >= NV_10 ? 0x0062 : 0x0042,
 179                                 NULL, 0, &object);
 180        if (ret)
 181                return ret;
 182
 183        ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvClipRect,
 184                                 0x0019, NULL, 0, &object);
 185        if (ret)
 186                return ret;
 187
 188        ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvRop,
 189                                 0x0043, NULL, 0, &object);
 190        if (ret)
 191                return ret;
 192
 193        ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvImagePatt,
 194                                 0x0044, NULL, 0, &object);
 195        if (ret)
 196                return ret;
 197
 198        ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvGdiRect,
 199                                 0x004a, NULL, 0, &object);
 200        if (ret)
 201                return ret;
 202
 203        ret = nouveau_object_new(nv_object(chan->cli), NVDRM_CHAN, NvImageBlit,
 204                                 device->chipset >= 0x11 ? 0x009f : 0x005f,
 205                                 NULL, 0, &object);
 206        if (ret)
 207                return ret;
 208
 209        if (RING_SPACE(chan, 49)) {
 210                nouveau_fbcon_gpu_lockup(info);
 211                return 0;
 212        }
 213
 214        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 215        OUT_RING(chan, NvCtxSurf2D);
 216        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0184, 2);
 217        OUT_RING(chan, NvDmaFB);
 218        OUT_RING(chan, NvDmaFB);
 219        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 4);
 220        OUT_RING(chan, surface_fmt);
 221        OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16));
 222        OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
 223        OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
 224
 225        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 226        OUT_RING(chan, NvRop);
 227        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 1);
 228        OUT_RING(chan, 0x55);
 229
 230        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 231        OUT_RING(chan, NvImagePatt);
 232        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 8);
 233        OUT_RING(chan, pattern_fmt);
 234#ifdef __BIG_ENDIAN
 235        OUT_RING(chan, 2);
 236#else
 237        OUT_RING(chan, 1);
 238#endif
 239        OUT_RING(chan, 0);
 240        OUT_RING(chan, 1);
 241        OUT_RING(chan, ~0);
 242        OUT_RING(chan, ~0);
 243        OUT_RING(chan, ~0);
 244        OUT_RING(chan, ~0);
 245
 246        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
 247        OUT_RING(chan, NvClipRect);
 248        BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 2);
 249        OUT_RING(chan, 0);
 250        OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual);
 251
 252        BEGIN_NV04(chan, NvSubImageBlit, 0x0000, 1);
 253        OUT_RING(chan, NvImageBlit);
 254        BEGIN_NV04(chan, NvSubImageBlit, 0x019c, 1);
 255        OUT_RING(chan, NvCtxSurf2D);
 256        BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1);
 257        OUT_RING(chan, 3);
 258        if (device->chipset >= 0x11 /*XXX: oclass == 0x009f*/) {
 259                BEGIN_NV04(chan, NvSubImageBlit, 0x0120, 3);
 260                OUT_RING(chan, 0);
 261                OUT_RING(chan, 1);
 262                OUT_RING(chan, 2);
 263        }
 264
 265        BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1);
 266        OUT_RING(chan, NvGdiRect);
 267        BEGIN_NV04(chan, NvSubGdiRect, 0x0198, 1);
 268        OUT_RING(chan, NvCtxSurf2D);
 269        BEGIN_NV04(chan, NvSubGdiRect, 0x0188, 2);
 270        OUT_RING(chan, NvImagePatt);
 271        OUT_RING(chan, NvRop);
 272        BEGIN_NV04(chan, NvSubGdiRect, 0x0304, 1);
 273        OUT_RING(chan, 1);
 274        BEGIN_NV04(chan, NvSubGdiRect, 0x0300, 1);
 275        OUT_RING(chan, rect_fmt);
 276        BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
 277        OUT_RING(chan, 3);
 278
 279        FIRE_RING(chan);
 280
 281        return 0;
 282}
 283
 284