linux/drivers/gpu/drm/nouveau/dispnv50/base507c.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 "base.h"
  23
  24#include <nvif/cl507c.h>
  25#include <nvif/event.h>
  26#include <nvif/timer.h>
  27
  28#include <drm/drm_atomic_helper.h>
  29#include <drm/drm_fourcc.h>
  30#include <drm/drm_plane_helper.h>
  31
  32#include "nouveau_bo.h"
  33
  34void
  35base507c_update(struct nv50_wndw *wndw, u32 *interlock)
  36{
  37        u32 *push;
  38        if ((push = evo_wait(&wndw->wndw, 2))) {
  39                evo_mthd(push, 0x0080, 1);
  40                evo_data(push, interlock[NV50_DISP_INTERLOCK_CORE]);
  41                evo_kick(push, &wndw->wndw);
  42        }
  43}
  44
  45void
  46base507c_image_clr(struct nv50_wndw *wndw)
  47{
  48        u32 *push;
  49        if ((push = evo_wait(&wndw->wndw, 4))) {
  50                evo_mthd(push, 0x0084, 1);
  51                evo_data(push, 0x00000000);
  52                evo_mthd(push, 0x00c0, 1);
  53                evo_data(push, 0x00000000);
  54                evo_kick(push, &wndw->wndw);
  55        }
  56}
  57
  58static void
  59base507c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
  60{
  61        u32 *push;
  62        if ((push = evo_wait(&wndw->wndw, 13))) {
  63                evo_mthd(push, 0x0084, 1);
  64                evo_data(push, asyw->image.mode << 8 |
  65                               asyw->image.interval << 4);
  66                evo_mthd(push, 0x00c0, 1);
  67                evo_data(push, asyw->image.handle[0]);
  68                if (asyw->image.format == 0xca) {
  69                        evo_mthd(push, 0x0110, 2);
  70                        evo_data(push, 1);
  71                        evo_data(push, 0x6400);
  72                } else {
  73                        evo_mthd(push, 0x0110, 2);
  74                        evo_data(push, 0);
  75                        evo_data(push, 0);
  76                }
  77                evo_mthd(push, 0x0800, 5);
  78                evo_data(push, asyw->image.offset[0] >> 8);
  79                evo_data(push, 0x00000000);
  80                evo_data(push, asyw->image.h << 16 | asyw->image.w);
  81                evo_data(push, asyw->image.layout << 20 |
  82                               (asyw->image.pitch[0] >> 8) << 8 |
  83                               asyw->image.blocks[0] << 8 |
  84                               asyw->image.blockh);
  85                evo_data(push, asyw->image.kind << 16 |
  86                               asyw->image.format << 8);
  87                evo_kick(push, &wndw->wndw);
  88        }
  89}
  90
  91void
  92base507c_xlut_clr(struct nv50_wndw *wndw)
  93{
  94        u32 *push;
  95        if ((push = evo_wait(&wndw->wndw, 2))) {
  96                evo_mthd(push, 0x00e0, 1);
  97                evo_data(push, 0x00000000);
  98                evo_kick(push, &wndw->wndw);
  99        }
 100}
 101
 102void
 103base507c_xlut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 104{
 105        u32 *push;
 106        if ((push = evo_wait(&wndw->wndw, 2))) {
 107                evo_mthd(push, 0x00e0, 1);
 108                evo_data(push, 0x40000000);
 109                evo_kick(push, &wndw->wndw);
 110        }
 111}
 112
 113int
 114base507c_ntfy_wait_begun(struct nouveau_bo *bo, u32 offset,
 115                         struct nvif_device *device)
 116{
 117        s64 time = nvif_msec(device, 2000ULL,
 118                u32 data = nouveau_bo_rd32(bo, offset / 4);
 119                if ((data & 0xc0000000) == 0x40000000)
 120                        break;
 121                usleep_range(1, 2);
 122        );
 123        return time < 0 ? time : 0;
 124}
 125
 126void
 127base507c_ntfy_clr(struct nv50_wndw *wndw)
 128{
 129        u32 *push;
 130        if ((push = evo_wait(&wndw->wndw, 2))) {
 131                evo_mthd(push, 0x00a4, 1);
 132                evo_data(push, 0x00000000);
 133                evo_kick(push, &wndw->wndw);
 134        }
 135}
 136
 137void
 138base507c_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 139{
 140        u32 *push;
 141        if ((push = evo_wait(&wndw->wndw, 3))) {
 142                evo_mthd(push, 0x00a0, 2);
 143                evo_data(push, asyw->ntfy.awaken << 30 | asyw->ntfy.offset);
 144                evo_data(push, asyw->ntfy.handle);
 145                evo_kick(push, &wndw->wndw);
 146        }
 147}
 148
 149void
 150base507c_ntfy_reset(struct nouveau_bo *bo, u32 offset)
 151{
 152        nouveau_bo_wr32(bo, offset / 4, 0x00000000);
 153}
 154
 155void
 156base507c_sema_clr(struct nv50_wndw *wndw)
 157{
 158        u32 *push;
 159        if ((push = evo_wait(&wndw->wndw, 2))) {
 160                evo_mthd(push, 0x0094, 1);
 161                evo_data(push, 0x00000000);
 162                evo_kick(push, &wndw->wndw);
 163        }
 164}
 165
 166void
 167base507c_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 168{
 169        u32 *push;
 170        if ((push = evo_wait(&wndw->wndw, 5))) {
 171                evo_mthd(push, 0x0088, 4);
 172                evo_data(push, asyw->sema.offset);
 173                evo_data(push, asyw->sema.acquire);
 174                evo_data(push, asyw->sema.release);
 175                evo_data(push, asyw->sema.handle);
 176                evo_kick(push, &wndw->wndw);
 177        }
 178}
 179
 180void
 181base507c_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
 182                 struct nv50_head_atom *asyh)
 183{
 184        asyh->base.cpp = 0;
 185}
 186
 187int
 188base507c_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
 189                 struct nv50_head_atom *asyh)
 190{
 191        const struct drm_framebuffer *fb = asyw->state.fb;
 192        int ret;
 193
 194        ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
 195                                                  DRM_PLANE_HELPER_NO_SCALING,
 196                                                  DRM_PLANE_HELPER_NO_SCALING,
 197                                                  false, true);
 198        if (ret)
 199                return ret;
 200
 201        if (!wndw->func->ilut) {
 202                if ((asyh->base.cpp != 1) ^ (fb->format->cpp[0] != 1))
 203                        asyh->state.color_mgmt_changed = true;
 204        }
 205
 206        asyh->base.depth = fb->format->depth;
 207        asyh->base.cpp = fb->format->cpp[0];
 208        asyh->base.x = asyw->state.src.x1 >> 16;
 209        asyh->base.y = asyw->state.src.y1 >> 16;
 210        asyh->base.w = asyw->state.fb->width;
 211        asyh->base.h = asyw->state.fb->height;
 212
 213        /* Some newer formats, esp FP16 ones, don't have a
 214         * "depth". There's nothing that really makes sense there
 215         * either, so just set it to the implicit bit count.
 216         */
 217        if (!asyh->base.depth)
 218                asyh->base.depth = asyh->base.cpp * 8;
 219
 220        return 0;
 221}
 222
 223const u32
 224base507c_format[] = {
 225        DRM_FORMAT_C8,
 226        DRM_FORMAT_RGB565,
 227        DRM_FORMAT_XRGB1555,
 228        DRM_FORMAT_ARGB1555,
 229        DRM_FORMAT_XRGB8888,
 230        DRM_FORMAT_ARGB8888,
 231        DRM_FORMAT_XBGR2101010,
 232        DRM_FORMAT_ABGR2101010,
 233        DRM_FORMAT_XBGR8888,
 234        DRM_FORMAT_ABGR8888,
 235        DRM_FORMAT_XBGR16161616F,
 236        DRM_FORMAT_ABGR16161616F,
 237        0
 238};
 239
 240static const struct nv50_wndw_func
 241base507c = {
 242        .acquire = base507c_acquire,
 243        .release = base507c_release,
 244        .sema_set = base507c_sema_set,
 245        .sema_clr = base507c_sema_clr,
 246        .ntfy_reset = base507c_ntfy_reset,
 247        .ntfy_set = base507c_ntfy_set,
 248        .ntfy_clr = base507c_ntfy_clr,
 249        .ntfy_wait_begun = base507c_ntfy_wait_begun,
 250        .olut_core = 1,
 251        .xlut_set = base507c_xlut_set,
 252        .xlut_clr = base507c_xlut_clr,
 253        .image_set = base507c_image_set,
 254        .image_clr = base507c_image_clr,
 255        .update = base507c_update,
 256};
 257
 258int
 259base507c_new_(const struct nv50_wndw_func *func, const u32 *format,
 260              struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
 261              struct nv50_wndw **pwndw)
 262{
 263        struct nv50_disp_base_channel_dma_v0 args = {
 264                .head = head,
 265        };
 266        struct nouveau_display *disp = nouveau_display(drm->dev);
 267        struct nv50_disp *disp50 = nv50_disp(drm->dev);
 268        struct nv50_wndw *wndw;
 269        int ret;
 270
 271        ret = nv50_wndw_new_(func, drm->dev, DRM_PLANE_TYPE_PRIMARY,
 272                             "base", head, format, BIT(head),
 273                             NV50_DISP_INTERLOCK_BASE, interlock_data, &wndw);
 274        if (*pwndw = wndw, ret)
 275                return ret;
 276
 277        ret = nv50_dmac_create(&drm->client.device, &disp->disp.object,
 278                               &oclass, head, &args, sizeof(args),
 279                               disp50->sync->bo.offset, &wndw->wndw);
 280        if (ret) {
 281                NV_ERROR(drm, "base%04x allocation failed: %d\n", oclass, ret);
 282                return ret;
 283        }
 284
 285        ret = nvif_notify_init(&wndw->wndw.base.user, wndw->notify.func,
 286                               false, NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT,
 287                               &(struct nvif_notify_uevent_req) {},
 288                               sizeof(struct nvif_notify_uevent_req),
 289                               sizeof(struct nvif_notify_uevent_rep),
 290                               &wndw->notify);
 291        if (ret)
 292                return ret;
 293
 294        wndw->ntfy = NV50_DISP_BASE_NTFY(wndw->id);
 295        wndw->sema = NV50_DISP_BASE_SEM0(wndw->id);
 296        wndw->data = 0x00000000;
 297        return 0;
 298}
 299
 300int
 301base507c_new(struct nouveau_drm *drm, int head, s32 oclass,
 302             struct nv50_wndw **pwndw)
 303{
 304        return base507c_new_(&base507c, base507c_format, drm, head, oclass,
 305                             0x00000002 << (head * 8), pwndw);
 306}
 307