linux/drivers/gpu/drm/nouveau/dispnv50/headc37d.c
<<
>>
Prefs
   1/*
   2 * Copyright 2018 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#include "head.h"
  23#include "atom.h"
  24#include "core.h"
  25
  26#include <nvif/pushc37b.h>
  27
  28#include <nvhw/class/clc37d.h>
  29
  30static int
  31headc37d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
  32{
  33        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  34        const int i = head->base.index;
  35        u8 depth;
  36        int ret;
  37
  38        /*XXX: This is a dirty hack until OR depth handling is
  39         *     improved later for deep colour etc.
  40         */
  41        switch (asyh->or.depth) {
  42        case 6: depth = 5; break;
  43        case 5: depth = 4; break;
  44        case 2: depth = 1; break;
  45        case 0: depth = 4; break;
  46        default:
  47                depth = asyh->or.depth;
  48                WARN_ON(1);
  49                break;
  50        }
  51
  52        if ((ret = PUSH_WAIT(push, 2)))
  53                return ret;
  54
  55        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTROL_OUTPUT_RESOURCE(i),
  56                  NVVAL(NVC37D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, CRC_MODE, asyh->or.crc_raster) |
  57                  NVVAL(NVC37D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, HSYNC_POLARITY, asyh->or.nhsync) |
  58                  NVVAL(NVC37D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, VSYNC_POLARITY, asyh->or.nvsync) |
  59                  NVVAL(NVC37D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, PIXEL_DEPTH, depth) |
  60                  NVDEF(NVC37D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, COLOR_SPACE_OVERRIDE, DISABLE));
  61        return 0;
  62}
  63
  64static int
  65headc37d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
  66{
  67        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  68        const int i = head->base.index;
  69        int ret;
  70
  71        if ((ret = PUSH_WAIT(push, 2)))
  72                return ret;
  73
  74        PUSH_MTHD(push, NVC37D, HEAD_SET_PROCAMP(i),
  75                  NVDEF(NVC37D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
  76                  NVDEF(NVC37D, HEAD_SET_PROCAMP, CHROMA_LPF, DISABLE) |
  77                  NVVAL(NVC37D, HEAD_SET_PROCAMP, SAT_COS, asyh->procamp.sat.cos) |
  78                  NVVAL(NVC37D, HEAD_SET_PROCAMP, SAT_SINE, asyh->procamp.sat.sin) |
  79                  NVDEF(NVC37D, HEAD_SET_PROCAMP, DYNAMIC_RANGE, VESA) |
  80                  NVDEF(NVC37D, HEAD_SET_PROCAMP, RANGE_COMPRESSION, DISABLE) |
  81                  NVDEF(NVC37D, HEAD_SET_PROCAMP, BLACK_LEVEL, GRAPHICS));
  82        return 0;
  83}
  84
  85int
  86headc37d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
  87{
  88        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  89        const int i = head->base.index;
  90        int ret;
  91
  92        if ((ret = PUSH_WAIT(push, 2)))
  93                return ret;
  94
  95        PUSH_MTHD(push, NVC37D, HEAD_SET_DITHER_CONTROL(i),
  96                  NVVAL(NVC37D, HEAD_SET_DITHER_CONTROL, ENABLE, asyh->dither.enable) |
  97                  NVVAL(NVC37D, HEAD_SET_DITHER_CONTROL, BITS, asyh->dither.bits) |
  98                  NVDEF(NVC37D, HEAD_SET_DITHER_CONTROL, OFFSET_ENABLE, DISABLE) |
  99                  NVVAL(NVC37D, HEAD_SET_DITHER_CONTROL, MODE, asyh->dither.mode) |
 100                  NVVAL(NVC37D, HEAD_SET_DITHER_CONTROL, PHASE, 0));
 101        return 0;
 102}
 103
 104int
 105headc37d_curs_clr(struct nv50_head *head)
 106{
 107        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
 108        const int i = head->base.index;
 109        int ret;
 110
 111        if ((ret = PUSH_WAIT(push, 4)))
 112                return ret;
 113
 114        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTROL_CURSOR(i),
 115                  NVDEF(NVC37D, HEAD_SET_CONTROL_CURSOR, ENABLE, DISABLE) |
 116                  NVDEF(NVC37D, HEAD_SET_CONTROL_CURSOR, FORMAT, A8R8G8B8));
 117
 118        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CURSOR(i, 0), 0x00000000);
 119        return 0;
 120}
 121
 122int
 123headc37d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 124{
 125        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
 126        const int i = head->base.index;
 127        int ret;
 128
 129        if ((ret = PUSH_WAIT(push, 7)))
 130                return ret;
 131
 132        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTROL_CURSOR(i),
 133                  NVDEF(NVC37D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) |
 134                  NVVAL(NVC37D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) |
 135                  NVVAL(NVC37D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) |
 136                  NVVAL(NVC37D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) |
 137                  NVVAL(NVC37D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0) |
 138                  NVDEF(NVC37D, HEAD_SET_CONTROL_CURSOR, DE_GAMMA, NONE),
 139
 140                                HEAD_SET_CONTROL_CURSOR_COMPOSITION(i),
 141                  NVVAL(NVC37D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, K1, 0xff) |
 142                  NVDEF(NVC37D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, CURSOR_COLOR_FACTOR_SELECT,
 143                                                                     K1) |
 144                  NVDEF(NVC37D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, VIEWPORT_COLOR_FACTOR_SELECT,
 145                                                                     NEG_K1_TIMES_SRC) |
 146                  NVDEF(NVC37D, HEAD_SET_CONTROL_CURSOR_COMPOSITION, MODE, BLEND));
 147
 148        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CURSOR(i, 0), asyh->curs.handle);
 149        PUSH_MTHD(push, NVC37D, HEAD_SET_OFFSET_CURSOR(i, 0), asyh->curs.offset >> 8);
 150        return 0;
 151}
 152
 153int
 154headc37d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
 155                     struct nv50_head_atom *asyh)
 156{
 157        asyh->curs.format = asyw->image.format;
 158        return 0;
 159}
 160
 161static int
 162headc37d_olut_clr(struct nv50_head *head)
 163{
 164        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
 165        const int i = head->base.index;
 166        int ret;
 167
 168        if ((ret = PUSH_WAIT(push, 2)))
 169                return ret;
 170
 171        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_OUTPUT_LUT(i), 0x00000000);
 172        return 0;
 173}
 174
 175static int
 176headc37d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 177{
 178        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
 179        const int i = head->base.index;
 180        int ret;
 181
 182        if ((ret = PUSH_WAIT(push, 4)))
 183                return ret;
 184
 185        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTROL_OUTPUT_LUT(i),
 186                  NVVAL(NVC37D, HEAD_SET_CONTROL_OUTPUT_LUT, SIZE, asyh->olut.size) |
 187                  NVVAL(NVC37D, HEAD_SET_CONTROL_OUTPUT_LUT, RANGE, asyh->olut.range) |
 188                  NVVAL(NVC37D, HEAD_SET_CONTROL_OUTPUT_LUT, OUTPUT_MODE, asyh->olut.output_mode),
 189
 190                                HEAD_SET_OFFSET_OUTPUT_LUT(i), asyh->olut.offset >> 8,
 191                                HEAD_SET_CONTEXT_DMA_OUTPUT_LUT(i), asyh->olut.handle);
 192        return 0;
 193}
 194
 195static bool
 196headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 197{
 198        if (size != 256 && size != 1024)
 199                return false;
 200
 201        asyh->olut.size = size == 1024 ? NVC37D_HEAD_SET_CONTROL_OUTPUT_LUT_SIZE_SIZE_1025 :
 202                                         NVC37D_HEAD_SET_CONTROL_OUTPUT_LUT_SIZE_SIZE_257;
 203        asyh->olut.range = NVC37D_HEAD_SET_CONTROL_OUTPUT_LUT_RANGE_UNITY;
 204        asyh->olut.output_mode = NVC37D_HEAD_SET_CONTROL_OUTPUT_LUT_OUTPUT_MODE_INTERPOLATE;
 205        asyh->olut.load = head907d_olut_load;
 206        return true;
 207}
 208
 209static int
 210headc37d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
 211{
 212        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
 213        struct nv50_head_mode *m = &asyh->mode;
 214        const int i = head->base.index;
 215        int ret;
 216
 217        if ((ret = PUSH_WAIT(push, 15)))
 218                return ret;
 219
 220        PUSH_MTHD(push, NVC37D, HEAD_SET_RASTER_SIZE(i),
 221                  NVVAL(NVC37D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
 222                  NVVAL(NVC37D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
 223
 224                                HEAD_SET_RASTER_SYNC_END(i),
 225                  NVVAL(NVC37D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
 226                  NVVAL(NVC37D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
 227
 228                                HEAD_SET_RASTER_BLANK_END(i),
 229                  NVVAL(NVC37D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
 230                  NVVAL(NVC37D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
 231
 232                                HEAD_SET_RASTER_BLANK_START(i),
 233                  NVVAL(NVC37D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
 234                  NVVAL(NVC37D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks));
 235
 236        //XXX:
 237        PUSH_NVSQ(push, NVC37D, 0x2074 + (i * 0x400), m->v.blank2e << 16 | m->v.blank2s);
 238        PUSH_NVSQ(push, NVC37D, 0x2008 + (i * 0x400), m->interlace);
 239
 240        PUSH_MTHD(push, NVC37D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i),
 241                  NVVAL(NVC37D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000));
 242
 243        PUSH_MTHD(push, NVC37D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(i),
 244                  NVVAL(NVC37D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, HERTZ, m->clock * 1000));
 245
 246        /*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
 247        PUSH_MTHD(push, NVC37D, HEAD_SET_HEAD_USAGE_BOUNDS(i),
 248                  NVDEF(NVC37D, HEAD_SET_HEAD_USAGE_BOUNDS, CURSOR, USAGE_W256_H256) |
 249                  NVDEF(NVC37D, HEAD_SET_HEAD_USAGE_BOUNDS, OUTPUT_LUT, USAGE_1025) |
 250                  NVDEF(NVC37D, HEAD_SET_HEAD_USAGE_BOUNDS, UPSCALING_ALLOWED, TRUE));
 251        return 0;
 252}
 253
 254int
 255headc37d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
 256{
 257        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
 258        const int i = head->base.index;
 259        int ret;
 260
 261        if ((ret = PUSH_WAIT(push, 4)))
 262                return ret;
 263
 264        PUSH_MTHD(push, NVC37D, HEAD_SET_VIEWPORT_SIZE_IN(i),
 265                  NVVAL(NVC37D, HEAD_SET_VIEWPORT_SIZE_IN, WIDTH, asyh->view.iW) |
 266                  NVVAL(NVC37D, HEAD_SET_VIEWPORT_SIZE_IN, HEIGHT, asyh->view.iH));
 267
 268        PUSH_MTHD(push, NVC37D, HEAD_SET_VIEWPORT_SIZE_OUT(i),
 269                  NVVAL(NVC37D, HEAD_SET_VIEWPORT_SIZE_OUT, WIDTH, asyh->view.oW) |
 270                  NVVAL(NVC37D, HEAD_SET_VIEWPORT_SIZE_OUT, HEIGHT, asyh->view.oH));
 271        return 0;
 272}
 273
 274void
 275headc37d_static_wndw_map(struct nv50_head *head, struct nv50_head_atom *asyh)
 276{
 277        int i, end;
 278
 279        for (i = head->base.index * 2, end = i + 2; i < end; i++)
 280                asyh->wndw.owned |= BIT(i);
 281}
 282
 283const struct nv50_head_func
 284headc37d = {
 285        .view = headc37d_view,
 286        .mode = headc37d_mode,
 287        .olut = headc37d_olut,
 288        .olut_size = 1024,
 289        .olut_set = headc37d_olut_set,
 290        .olut_clr = headc37d_olut_clr,
 291        .curs_layout = head917d_curs_layout,
 292        .curs_format = headc37d_curs_format,
 293        .curs_set = headc37d_curs_set,
 294        .curs_clr = headc37d_curs_clr,
 295        .dither = headc37d_dither,
 296        .procamp = headc37d_procamp,
 297        .or = headc37d_or,
 298        .static_wndw_map = headc37d_static_wndw_map,
 299};
 300