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#define NVIF_DEBUG_PRINT_DISABLE
  25#include "nouveau_drv.h"
  26#include "nouveau_dma.h"
  27#include "nouveau_fbcon.h"
  28
  29#include <nvif/push006c.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->helper.dev);
  36        struct nouveau_channel *chan = drm->channel;
  37        struct nvif_push *push = chan->chan.push;
  38        int ret;
  39
  40        ret = PUSH_WAIT(push, 4);
  41        if (ret)
  42                return ret;
  43
  44        PUSH_NVSQ(push, NV05F, 0x0300, (region->sy << 16) | region->sx,
  45                               0x0304, (region->dy << 16) | region->dx,
  46                               0x0308, (region->height << 16) | region->width);
  47        PUSH_KICK(push);
  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->helper.dev);
  56        struct nouveau_channel *chan = drm->channel;
  57        struct nvif_push *push = chan->chan.push;
  58        int ret;
  59
  60        ret = PUSH_WAIT(push, 7);
  61        if (ret)
  62                return ret;
  63
  64        PUSH_NVSQ(push, NV04A, 0x02fc, (rect->rop != ROP_COPY) ? 1 : 3);
  65        if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
  66            info->fix.visual == FB_VISUAL_DIRECTCOLOR)
  67                PUSH_NVSQ(push, NV04A, 0x03fc, ((uint32_t *)info->pseudo_palette)[rect->color]);
  68        else
  69                PUSH_NVSQ(push, NV04A, 0x03fc, rect->color);
  70        PUSH_NVSQ(push, NV04A, 0x0400, (rect->dx << 16) | rect->dy,
  71                               0x0404, (rect->width << 16) | rect->height);
  72        PUSH_KICK(push);
  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        struct nvif_push *push = chan->chan.push;
  83        uint32_t fg;
  84        uint32_t bg;
  85        uint32_t dsize;
  86        uint32_t *data = (uint32_t *)image->data;
  87        int ret;
  88
  89        if (image->depth != 1)
  90                return -ENODEV;
  91
  92        ret = PUSH_WAIT(push, 8);
  93        if (ret)
  94                return ret;
  95
  96        if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
  97            info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
  98                fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
  99                bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
 100        } else {
 101                fg = image->fg_color;
 102                bg = image->bg_color;
 103        }
 104
 105        PUSH_NVSQ(push, NV04A, 0x0be4, (image->dy << 16) | (image->dx & 0xffff),
 106                               0x0be8, ((image->dy + image->height) << 16) |
 107                                       ((image->dx + image->width) & 0xffff),
 108                               0x0bec, bg,
 109                               0x0bf0, fg,
 110                               0x0bf4, (image->height << 16) | ALIGN(image->width, 8),
 111                               0x0bf8, (image->height << 16) | image->width,
 112                               0x0bfc, (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 = PUSH_WAIT(push, iter_len + 1);
 119                if (ret)
 120                        return ret;
 121
 122                PUSH_NVSQ(push, NV04A, 0x0c00, data, iter_len);
 123                data += iter_len;
 124                dsize -= iter_len;
 125        }
 126
 127        PUSH_KICK(push);
 128        return 0;
 129}
 130
 131int
 132nv04_fbcon_accel_init(struct fb_info *info)
 133{
 134        struct nouveau_fbdev *nfbdev = info->par;
 135        struct drm_device *dev = nfbdev->helper.dev;
 136        struct nouveau_drm *drm = nouveau_drm(dev);
 137        struct nouveau_channel *chan = drm->channel;
 138        struct nvif_device *device = &drm->client.device;
 139        struct nvif_push *push = chan->chan.push;
 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_ctor(&chan->user, "fbconCtxSurf2d", 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_ctor(&chan->user, "fbconCtxClip", 0x0019, 0x0019,
 178                               NULL, 0, &nfbdev->clip);
 179        if (ret)
 180                return ret;
 181
 182        ret = nvif_object_ctor(&chan->user, "fbconCtxRop", 0x0043, 0x0043,
 183                               NULL, 0, &nfbdev->rop);
 184        if (ret)
 185                return ret;
 186
 187        ret = nvif_object_ctor(&chan->user, "fbconCtxPatt", 0x0044, 0x0044,
 188                               NULL, 0, &nfbdev->patt);
 189        if (ret)
 190                return ret;
 191
 192        ret = nvif_object_ctor(&chan->user, "fbconGdiRectText", 0x004a, 0x004a,
 193                               NULL, 0, &nfbdev->gdi);
 194        if (ret)
 195                return ret;
 196
 197        ret = nvif_object_ctor(&chan->user, "fbconImageBlit", 0x005f,
 198                               device->info.chipset >= 0x11 ? 0x009f : 0x005f,
 199                               NULL, 0, &nfbdev->blit);
 200        if (ret)
 201                return ret;
 202
 203        if (PUSH_WAIT(push, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
 204                nouveau_fbcon_gpu_lockup(info);
 205                return 0;
 206        }
 207
 208        PUSH_NVSQ(push, NV042, 0x0000, nfbdev->surf2d.handle);
 209        PUSH_NVSQ(push, NV042, 0x0184, chan->vram.handle,
 210                               0x0188, chan->vram.handle);
 211        PUSH_NVSQ(push, NV042, 0x0300, surface_fmt,
 212                               0x0304, info->fix.line_length | (info->fix.line_length << 16),
 213                               0x0308, info->fix.smem_start - dev->mode_config.fb_base,
 214                               0x030c, info->fix.smem_start - dev->mode_config.fb_base);
 215
 216        PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle);
 217        PUSH_NVSQ(push, NV043, 0x0300, 0x55);
 218
 219        PUSH_NVSQ(push, NV044, 0x0000, nfbdev->patt.handle);
 220        PUSH_NVSQ(push, NV044, 0x0300, pattern_fmt,
 221#ifdef __BIG_ENDIAN
 222                               0x0304, 2,
 223#else
 224                               0x0304, 1,
 225#endif
 226                               0x0308, 0,
 227                               0x030c, 1,
 228                               0x0310, ~0,
 229                               0x0314, ~0,
 230                               0x0318, ~0,
 231                               0x031c, ~0);
 232
 233        PUSH_NVSQ(push, NV019, 0x0000, nfbdev->clip.handle);
 234        PUSH_NVSQ(push, NV019, 0x0300, 0,
 235                               0x0304, (info->var.yres_virtual << 16) | info->var.xres_virtual);
 236
 237        PUSH_NVSQ(push, NV05F, 0x0000, nfbdev->blit.handle);
 238        PUSH_NVSQ(push, NV05F, 0x019c, nfbdev->surf2d.handle);
 239        PUSH_NVSQ(push, NV05F, 0x02fc, 3);
 240        if (nfbdev->blit.oclass == 0x009f) {
 241                PUSH_NVSQ(push, NV09F, 0x0120, 0,
 242                                       0x0124, 1,
 243                                       0x0128, 2);
 244        }
 245
 246        PUSH_NVSQ(push, NV04A, 0x0000, nfbdev->gdi.handle);
 247        PUSH_NVSQ(push, NV04A, 0x0198, nfbdev->surf2d.handle);
 248        PUSH_NVSQ(push, NV04A, 0x0188, nfbdev->patt.handle,
 249                               0x018c, nfbdev->rop.handle);
 250        PUSH_NVSQ(push, NV04A, 0x0304, 1);
 251        PUSH_NVSQ(push, NV04A, 0x0300, rect_fmt);
 252        PUSH_NVSQ(push, NV04A, 0x02fc, 3);
 253
 254        PUSH_KICK(push);
 255        return 0;
 256}
 257
 258