linux/drivers/gpu/drm/nouveau/dispnv50/crc907d.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2#include <drm/drm_crtc.h>
   3
   4#include "crc.h"
   5#include "core.h"
   6#include "disp.h"
   7#include "head.h"
   8
   9#include <nvif/push507c.h>
  10
  11#include <nvhw/class/cl907d.h>
  12
  13#define CRC907D_MAX_ENTRIES 255
  14
  15struct crc907d_notifier {
  16        u32 status;
  17        u32 :32; /* reserved */
  18        struct crc907d_entry {
  19                u32 status;
  20                u32 compositor_crc;
  21                u32 output_crc[2];
  22        } entries[CRC907D_MAX_ENTRIES];
  23} __packed;
  24
  25static int
  26crc907d_set_src(struct nv50_head *head, int or,
  27                enum nv50_crc_source_type source,
  28                struct nv50_crc_notifier_ctx *ctx, u32 wndw)
  29{
  30        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  31        const int i = head->base.index;
  32        u32 crc_args = NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, CORE) |
  33                       NVDEF(NV907D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) |
  34                       NVDEF(NV907D, HEAD_SET_CRC_CONTROL, TIMESTAMP_MODE, FALSE) |
  35                       NVDEF(NV907D, HEAD_SET_CRC_CONTROL, SECONDARY_OUTPUT, NONE) |
  36                       NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE);
  37        int ret;
  38
  39        switch (source) {
  40        case NV50_CRC_SOURCE_TYPE_SOR:
  41                crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, SOR(or));
  42                break;
  43        case NV50_CRC_SOURCE_TYPE_PIOR:
  44                crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, PIOR(or));
  45                break;
  46        case NV50_CRC_SOURCE_TYPE_DAC:
  47                crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, DAC(or));
  48                break;
  49        case NV50_CRC_SOURCE_TYPE_RG:
  50                crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, RG(i));
  51                break;
  52        case NV50_CRC_SOURCE_TYPE_SF:
  53                crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, SF(i));
  54                break;
  55        case NV50_CRC_SOURCE_NONE:
  56                crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, NONE);
  57                break;
  58        }
  59
  60        if ((ret = PUSH_WAIT(push, 4)))
  61                return ret;
  62
  63        if (source) {
  64                PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx->ntfy.handle);
  65                PUSH_MTHD(push, NV907D, HEAD_SET_CRC_CONTROL(i), crc_args);
  66        } else {
  67                PUSH_MTHD(push, NV907D, HEAD_SET_CRC_CONTROL(i), crc_args);
  68                PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CRC(i), 0);
  69        }
  70
  71        return 0;
  72}
  73
  74static int
  75crc907d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx)
  76{
  77        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  78        const int i = head->base.index;
  79        int ret;
  80
  81        if ((ret = PUSH_WAIT(push, 2)))
  82                return ret;
  83
  84        PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx ? ctx->ntfy.handle : 0);
  85        return 0;
  86}
  87
  88static u32 crc907d_get_entry(struct nv50_head *head,
  89                             struct nv50_crc_notifier_ctx *ctx,
  90                             enum nv50_crc_source source, int idx)
  91{
  92        struct crc907d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
  93
  94        return ioread32_native(&notifier->entries[idx].output_crc[0]);
  95}
  96
  97static bool crc907d_ctx_finished(struct nv50_head *head,
  98                                 struct nv50_crc_notifier_ctx *ctx)
  99{
 100        struct nouveau_drm *drm = nouveau_drm(head->base.base.dev);
 101        struct crc907d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
 102        const u32 status = ioread32_native(&notifier->status);
 103        const u32 overflow = status & 0x0000003e;
 104
 105        if (!(status & 0x00000001))
 106                return false;
 107
 108        if (overflow) {
 109                const char *engine = NULL;
 110
 111                switch (overflow) {
 112                case 0x00000004: engine = "DSI"; break;
 113                case 0x00000008: engine = "Compositor"; break;
 114                case 0x00000010: engine = "CRC output 1"; break;
 115                case 0x00000020: engine = "CRC output 2"; break;
 116                }
 117
 118                if (engine)
 119                        NV_ERROR(drm,
 120                                 "CRC notifier context for head %d overflowed on %s: %x\n",
 121                                 head->base.index, engine, status);
 122                else
 123                        NV_ERROR(drm,
 124                                 "CRC notifier context for head %d overflowed: %x\n",
 125                                 head->base.index, status);
 126        }
 127
 128        NV_DEBUG(drm, "Head %d CRC context status: %x\n",
 129                 head->base.index, status);
 130
 131        return true;
 132}
 133
 134const struct nv50_crc_func crc907d = {
 135        .set_src = crc907d_set_src,
 136        .set_ctx = crc907d_set_ctx,
 137        .get_entry = crc907d_get_entry,
 138        .ctx_finished = crc907d_ctx_finished,
 139        .flip_threshold = CRC907D_MAX_ENTRIES - 10,
 140        .num_entries = CRC907D_MAX_ENTRIES,
 141        .notifier_len = sizeof(struct crc907d_notifier),
 142};
 143