linux/drivers/gpu/drm/nouveau/dispnv50/head507d.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 "core.h"
  24
  25void
  26head507d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
  27{
  28        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  29        u32 *push;
  30        if ((push = evo_wait(core, 2))) {
  31                evo_mthd(push, 0x08a8 + (head->base.index * 0x400), 1);
  32                evo_data(push, asyh->procamp.sat.sin << 20 |
  33                               asyh->procamp.sat.cos << 8);
  34                evo_kick(push, core);
  35        }
  36}
  37
  38void
  39head507d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
  40{
  41        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  42        u32 *push;
  43        if ((push = evo_wait(core, 2))) {
  44                evo_mthd(push, 0x08a0 + (head->base.index * 0x0400), 1);
  45                evo_data(push, asyh->dither.mode << 3 |
  46                               asyh->dither.bits << 1 |
  47                               asyh->dither.enable);
  48                evo_kick(push, core);
  49        }
  50}
  51
  52void
  53head507d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
  54{
  55        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  56        u32 bounds = 0;
  57        u32 *push;
  58
  59        if (asyh->ovly.cpp) {
  60                switch (asyh->ovly.cpp) {
  61                case 4: bounds |= 0x00000300; break;
  62                case 2: bounds |= 0x00000100; break;
  63                default:
  64                        WARN_ON(1);
  65                        break;
  66                }
  67                bounds |= 0x00000001;
  68        } else {
  69                bounds |= 0x00000100;
  70        }
  71
  72        if ((push = evo_wait(core, 2))) {
  73                evo_mthd(push, 0x0904 + head->base.index * 0x400, 1);
  74                evo_data(push, bounds);
  75                evo_kick(push, core);
  76        }
  77}
  78
  79void
  80head507d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
  81{
  82        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
  83        u32 bounds = 0;
  84        u32 *push;
  85
  86        if (asyh->base.cpp) {
  87                switch (asyh->base.cpp) {
  88                case 8: bounds |= 0x00000500; break;
  89                case 4: bounds |= 0x00000300; break;
  90                case 2: bounds |= 0x00000100; break;
  91                case 1: bounds |= 0x00000000; break;
  92                default:
  93                        WARN_ON(1);
  94                        break;
  95                }
  96                bounds |= 0x00000001;
  97        }
  98
  99        if ((push = evo_wait(core, 2))) {
 100                evo_mthd(push, 0x0900 + head->base.index * 0x400, 1);
 101                evo_data(push, bounds);
 102                evo_kick(push, core);
 103        }
 104}
 105
 106static void
 107head507d_curs_clr(struct nv50_head *head)
 108{
 109        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 110        u32 *push;
 111        if ((push = evo_wait(core, 2))) {
 112                evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
 113                evo_data(push, 0x05000000);
 114                evo_kick(push, core);
 115        }
 116}
 117
 118static void
 119head507d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 120{
 121        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 122        u32 *push;
 123        if ((push = evo_wait(core, 3))) {
 124                evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
 125                evo_data(push, 0x80000000 | asyh->curs.layout << 26 |
 126                                            asyh->curs.format << 24);
 127                evo_data(push, asyh->curs.offset >> 8);
 128                evo_kick(push, core);
 129        }
 130}
 131
 132int
 133head507d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
 134                     struct nv50_head_atom *asyh)
 135{
 136        switch (asyw->image.format) {
 137        case 0xcf: asyh->curs.format = 1; break;
 138        default:
 139                WARN_ON(1);
 140                return -EINVAL;
 141        }
 142        return 0;
 143}
 144
 145int
 146head507d_curs_layout(struct nv50_head *head, struct nv50_wndw_atom *asyw,
 147                     struct nv50_head_atom *asyh)
 148{
 149        switch (asyw->image.w) {
 150        case 32: asyh->curs.layout = 0; break;
 151        case 64: asyh->curs.layout = 1; break;
 152        default:
 153                return -EINVAL;
 154        }
 155        return 0;
 156}
 157
 158void
 159head507d_core_clr(struct nv50_head *head)
 160{
 161        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 162        u32 *push;
 163        if ((push = evo_wait(core, 2))) {
 164                evo_mthd(push, 0x0874 + head->base.index * 0x400, 1);
 165                evo_data(push, 0x00000000);
 166                evo_kick(push, core);
 167        }
 168}
 169
 170static void
 171head507d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 172{
 173        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 174        u32 *push;
 175        if ((push = evo_wait(core, 9))) {
 176                evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
 177                evo_data(push, asyh->core.offset >> 8);
 178                evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
 179                evo_data(push, asyh->core.h << 16 | asyh->core.w);
 180                evo_data(push, asyh->core.layout << 20 |
 181                               (asyh->core.pitch >> 8) << 8 |
 182                               asyh->core.blocks << 8 |
 183                               asyh->core.blockh);
 184                evo_data(push, asyh->core.kind << 16 |
 185                               asyh->core.format << 8);
 186                evo_data(push, asyh->core.handle);
 187                evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
 188                evo_data(push, asyh->core.y << 16 | asyh->core.x);
 189                evo_kick(push, core);
 190
 191                /* EVO will complain with INVALID_STATE if we have an
 192                 * active cursor and (re)specify HeadSetContextDmaIso
 193                 * without also updating HeadSetOffsetCursor.
 194                 */
 195                asyh->set.curs = asyh->curs.visible;
 196                asyh->set.olut = asyh->olut.handle != 0;
 197        }
 198}
 199
 200void
 201head507d_core_calc(struct nv50_head *head, struct nv50_head_atom *asyh)
 202{
 203        struct nv50_disp *disp = nv50_disp(head->base.base.dev);
 204        if ((asyh->core.visible = (asyh->base.cpp != 0))) {
 205                asyh->core.x = asyh->base.x;
 206                asyh->core.y = asyh->base.y;
 207                asyh->core.w = asyh->base.w;
 208                asyh->core.h = asyh->base.h;
 209        } else
 210        if ((asyh->core.visible = (asyh->ovly.cpp != 0)) ||
 211            (asyh->core.visible = asyh->curs.visible)) {
 212                /*XXX: We need to either find some way of having the
 213                 *     primary base layer appear black, while still
 214                 *     being able to display the other layers, or we
 215                 *     need to allocate a dummy black surface here.
 216                 */
 217                asyh->core.x = 0;
 218                asyh->core.y = 0;
 219                asyh->core.w = asyh->state.mode.hdisplay;
 220                asyh->core.h = asyh->state.mode.vdisplay;
 221        }
 222        asyh->core.handle = disp->core->chan.vram.handle;
 223        asyh->core.offset = 0;
 224        asyh->core.format = 0xcf;
 225        asyh->core.kind = 0;
 226        asyh->core.layout = 1;
 227        asyh->core.blockh = 0;
 228        asyh->core.blocks = 0;
 229        asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
 230}
 231
 232static void
 233head507d_olut_clr(struct nv50_head *head)
 234{
 235        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 236        u32 *push;
 237        if ((push = evo_wait(core, 2))) {
 238                evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
 239                evo_data(push, 0x00000000);
 240                evo_kick(push, core);
 241        }
 242}
 243
 244static void
 245head507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 246{
 247        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 248        u32 *push;
 249        if ((push = evo_wait(core, 3))) {
 250                evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
 251                evo_data(push, 0x80000000 | asyh->olut.mode << 30);
 252                evo_data(push, asyh->olut.offset >> 8);
 253                evo_kick(push, core);
 254        }
 255}
 256
 257static void
 258head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
 259{
 260        for (; size--; in++, mem += 8) {
 261                writew(drm_color_lut_extract(in->  red, 11) << 3, mem + 0);
 262                writew(drm_color_lut_extract(in->green, 11) << 3, mem + 2);
 263                writew(drm_color_lut_extract(in-> blue, 11) << 3, mem + 4);
 264        }
 265
 266        /* INTERPOLATE modes require a "next" entry to interpolate with,
 267         * so we replicate the last entry to deal with this for now.
 268         */
 269        writew(readw(mem - 8), mem + 0);
 270        writew(readw(mem - 6), mem + 2);
 271        writew(readw(mem - 4), mem + 4);
 272}
 273
 274void
 275head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
 276{
 277        if (asyh->base.cpp == 1)
 278                asyh->olut.mode = 0;
 279        else
 280                asyh->olut.mode = 1;
 281
 282        asyh->olut.load = head507d_olut_load;
 283}
 284
 285void
 286head507d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
 287{
 288        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 289        struct nv50_head_mode *m = &asyh->mode;
 290        u32 *push;
 291        if ((push = evo_wait(core, 13))) {
 292                evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2);
 293                evo_data(push, 0x00800000 | m->clock);
 294                evo_data(push, m->interlace ? 0x00000002 : 0x00000000);
 295                evo_mthd(push, 0x0810 + (head->base.index * 0x400), 7);
 296                evo_data(push, 0x00000000);
 297                evo_data(push, m->v.active  << 16 | m->h.active );
 298                evo_data(push, m->v.synce   << 16 | m->h.synce  );
 299                evo_data(push, m->v.blanke  << 16 | m->h.blanke );
 300                evo_data(push, m->v.blanks  << 16 | m->h.blanks );
 301                evo_data(push, m->v.blank2e << 16 | m->v.blank2s);
 302                evo_data(push, asyh->mode.v.blankus);
 303                evo_mthd(push, 0x082c + (head->base.index * 0x400), 1);
 304                evo_data(push, 0x00000000);
 305                evo_kick(push, core);
 306        }
 307}
 308
 309void
 310head507d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
 311{
 312        struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
 313        u32 *push;
 314        if ((push = evo_wait(core, 7))) {
 315                evo_mthd(push, 0x08a4 + (head->base.index * 0x400), 1);
 316                evo_data(push, 0x00000000);
 317                evo_mthd(push, 0x08c8 + (head->base.index * 0x400), 1);
 318                evo_data(push, asyh->view.iH << 16 | asyh->view.iW);
 319                evo_mthd(push, 0x08d8 + (head->base.index * 0x400), 2);
 320                evo_data(push, asyh->view.oH << 16 | asyh->view.oW);
 321                evo_data(push, asyh->view.oH << 16 | asyh->view.oW);
 322                evo_kick(push, core);
 323        }
 324}
 325
 326const struct nv50_head_func
 327head507d = {
 328        .view = head507d_view,
 329        .mode = head507d_mode,
 330        .olut = head507d_olut,
 331        .olut_set = head507d_olut_set,
 332        .olut_clr = head507d_olut_clr,
 333        .core_calc = head507d_core_calc,
 334        .core_set = head507d_core_set,
 335        .core_clr = head507d_core_clr,
 336        .curs_layout = head507d_curs_layout,
 337        .curs_format = head507d_curs_format,
 338        .curs_set = head507d_curs_set,
 339        .curs_clr = head507d_curs_clr,
 340        .base = head507d_base,
 341        .ovly = head507d_ovly,
 342        .dither = head507d_dither,
 343        .procamp = head507d_procamp,
 344};
 345