linux/drivers/gpu/drm/nouveau/dispnv50/headc57d.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
  26static void
  27headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
  28{
  29        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  30        u32 *push;
  31        if ((push = evo_wait(core, 2))) {
  32                /*XXX: This is a dirty hack until OR depth handling is
  33                 *     improved later for deep colour etc.
  34                 */
  35                switch (asyh->or.depth) {
  36                case 6: asyh->or.depth = 5; break;
  37                case 5: asyh->or.depth = 4; break;
  38                case 2: asyh->or.depth = 1; break;
  39                case 0: asyh->or.depth = 4; break;
  40                default:
  41                        WARN_ON(1);
  42                        break;
  43                }
  44
  45                evo_mthd(push, 0x2004 + (head->base.index * 0x400), 1);
  46                evo_data(push, 0xfc000001 |
  47                               asyh->or.depth << 4 |
  48                               asyh->or.nvsync << 3 |
  49                               asyh->or.nhsync << 2);
  50                evo_kick(push, core);
  51        }
  52}
  53
  54static void
  55headc57d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
  56{
  57        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  58        u32 *push;
  59        if ((push = evo_wait(core, 2))) {
  60                evo_mthd(push, 0x2000 + (head->base.index * 0x400), 1);
  61#if 0
  62                evo_data(push, 0x80000000 |
  63                               asyh->procamp.sat.sin << 16 |
  64                               asyh->procamp.sat.cos << 4);
  65#else
  66                evo_data(push, 0);
  67#endif
  68                evo_kick(push, core);
  69        }
  70}
  71
  72void
  73headc57d_olut_clr(struct nv50_head *head)
  74{
  75        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  76        u32 *push;
  77        if ((push = evo_wait(core, 2))) {
  78                evo_mthd(push, 0x2288 + (head->base.index * 0x400), 1);
  79                evo_data(push, 0x00000000);
  80                evo_kick(push, core);
  81        }
  82}
  83
  84void
  85headc57d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
  86{
  87        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  88        u32 *push;
  89        if ((push = evo_wait(core, 4))) {
  90                evo_mthd(push, 0x2280 + (head->base.index * 0x400), 4);
  91                evo_data(push, asyh->olut.size << 8 |
  92                               asyh->olut.mode << 2 |
  93                               asyh->olut.output_mode);
  94                evo_data(push, 0xffffffff); /* FP_NORM_SCALE. */
  95                evo_data(push, asyh->olut.handle);
  96                evo_data(push, asyh->olut.offset >> 8);
  97                evo_kick(push, core);
  98        }
  99}
 100
 101static void
 102headc57d_olut_load_8(struct drm_color_lut *in, int size, void __iomem *mem)
 103{
 104        memset_io(mem, 0x00, 0x20); /* VSS header. */
 105        mem += 0x20;
 106
 107        while (size--) {
 108                u16 r = drm_color_lut_extract(in->  red + 0, 16);
 109                u16 g = drm_color_lut_extract(in->green + 0, 16);
 110                u16 b = drm_color_lut_extract(in-> blue + 0, 16);
 111                u16 ri = 0, gi = 0, bi = 0, i;
 112
 113                if (in++, size) {
 114                        ri = (drm_color_lut_extract(in->  red, 16) - r) / 4;
 115                        gi = (drm_color_lut_extract(in->green, 16) - g) / 4;
 116                        bi = (drm_color_lut_extract(in-> blue, 16) - b) / 4;
 117                }
 118
 119                for (i = 0; i < 4; i++, mem += 8) {
 120                        writew(r + ri * i, mem + 0);
 121                        writew(g + gi * i, mem + 2);
 122                        writew(b + bi * i, mem + 4);
 123                }
 124        }
 125
 126        /* INTERPOLATE modes require a "next" entry to interpolate with,
 127         * so we replicate the last entry to deal with this for now.
 128         */
 129        writew(readw(mem - 8), mem + 0);
 130        writew(readw(mem - 6), mem + 2);
 131        writew(readw(mem - 4), mem + 4);
 132}
 133
 134static void
 135headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
 136{
 137        memset_io(mem, 0x00, 0x20); /* VSS header. */
 138        mem += 0x20;
 139
 140        for (; size--; in++, mem += 0x08) {
 141                writew(drm_color_lut_extract(in->  red, 16), mem + 0);
 142                writew(drm_color_lut_extract(in->green, 16), mem + 2);
 143                writew(drm_color_lut_extract(in-> blue, 16), mem + 4);
 144        }
 145
 146        /* INTERPOLATE modes require a "next" entry to interpolate with,
 147         * so we replicate the last entry to deal with this for now.
 148         */
 149        writew(readw(mem - 8), mem + 0);
 150        writew(readw(mem - 6), mem + 2);
 151        writew(readw(mem - 4), mem + 4);
 152}
 153
 154bool
 155headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 156{
 157        if (size != 0 && size != 256 && size != 1024)
 158                return false;
 159
 160        asyh->olut.mode = 2; /* DIRECT10 */
 161        asyh->olut.size = 4 /* VSS header. */ + 1024 + 1 /* Entries. */;
 162        asyh->olut.output_mode = 1; /* INTERPOLATE_ENABLE. */
 163        if (size == 256)
 164                asyh->olut.load = headc57d_olut_load_8;
 165        else
 166                asyh->olut.load = headc57d_olut_load;
 167        return true;
 168}
 169
 170static void
 171headc57d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
 172{
 173        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 174        struct nv50_head_mode *m = &asyh->mode;
 175        u32 *push;
 176        if ((push = evo_wait(core, 13))) {
 177                evo_mthd(push, 0x2064 + (head->base.index * 0x400), 5);
 178                evo_data(push, (m->v.active  << 16) | m->h.active );
 179                evo_data(push, (m->v.synce   << 16) | m->h.synce  );
 180                evo_data(push, (m->v.blanke  << 16) | m->h.blanke );
 181                evo_data(push, (m->v.blanks  << 16) | m->h.blanks );
 182                evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
 183                evo_mthd(push, 0x2008 + (head->base.index * 0x400), 2);
 184                evo_data(push, m->interlace);
 185                evo_data(push, m->clock * 1000);
 186                evo_mthd(push, 0x2028 + (head->base.index * 0x400), 1);
 187                evo_data(push, m->clock * 1000);
 188                /*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
 189                evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1);
 190                evo_data(push, 0x00001014);
 191                evo_kick(push, core);
 192        }
 193}
 194
 195const struct nv50_head_func
 196headc57d = {
 197        .view = headc37d_view,
 198        .mode = headc57d_mode,
 199        .olut = headc57d_olut,
 200        .olut_identity = true,
 201        .olut_size = 1024,
 202        .olut_set = headc57d_olut_set,
 203        .olut_clr = headc57d_olut_clr,
 204        .curs_layout = head917d_curs_layout,
 205        .curs_format = headc37d_curs_format,
 206        .curs_set = headc37d_curs_set,
 207        .curs_clr = headc37d_curs_clr,
 208        .dither = headc37d_dither,
 209        .procamp = headc57d_procamp,
 210        .or = headc57d_or,
 211};
 212