linux/drivers/gpu/drm/nouveau/dispnv50/crcc37d.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/pushc37b.h>
  10
  11#include <nvhw/class/clc37d.h>
  12
  13#define CRCC37D_MAX_ENTRIES 2047
  14
  15struct crcc37d_notifier {
  16        u32 status;
  17
  18        /* reserved */
  19        u32 :32;
  20        u32 :32;
  21        u32 :32;
  22        u32 :32;
  23        u32 :32;
  24        u32 :32;
  25        u32 :32;
  26
  27        struct crcc37d_entry {
  28                u32 status[2];
  29                u32 :32; /* reserved */
  30                u32 compositor_crc;
  31                u32 rg_crc;
  32                u32 output_crc[2];
  33                u32 :32; /* reserved */
  34        } entries[CRCC37D_MAX_ENTRIES];
  35} __packed;
  36
  37static int
  38crcc37d_set_src(struct nv50_head *head, int or,
  39                enum nv50_crc_source_type source,
  40                struct nv50_crc_notifier_ctx *ctx, u32 wndw)
  41{
  42        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  43        const int i = head->base.index;
  44        u32 crc_args = NVVAL(NVC37D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, wndw) |
  45                       NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) |
  46                       NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, SECONDARY_CRC, NONE) |
  47                       NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE);
  48        int ret;
  49
  50        switch (source) {
  51        case NV50_CRC_SOURCE_TYPE_SOR:
  52                crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SOR(or));
  53                break;
  54        case NV50_CRC_SOURCE_TYPE_PIOR:
  55                crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, PIOR(or));
  56                break;
  57        case NV50_CRC_SOURCE_TYPE_SF:
  58                crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SF);
  59                break;
  60        default:
  61                break;
  62        }
  63
  64        if ((ret = PUSH_WAIT(push, 4)))
  65                return ret;
  66
  67        if (source) {
  68                PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx->ntfy.handle);
  69                PUSH_MTHD(push, NVC37D, HEAD_SET_CRC_CONTROL(i), crc_args);
  70        } else {
  71                PUSH_MTHD(push, NVC37D, HEAD_SET_CRC_CONTROL(i), 0);
  72                PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), 0);
  73        }
  74
  75        return 0;
  76}
  77
  78static int
  79crcc37d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx)
  80{
  81        struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  82        const int i = head->base.index;
  83        int ret;
  84
  85        if ((ret = PUSH_WAIT(push, 2)))
  86                return ret;
  87
  88        PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx ? ctx->ntfy.handle : 0);
  89        return 0;
  90}
  91
  92static u32 crcc37d_get_entry(struct nv50_head *head,
  93                             struct nv50_crc_notifier_ctx *ctx,
  94                             enum nv50_crc_source source, int idx)
  95{
  96        struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
  97        struct crcc37d_entry __iomem *entry = &notifier->entries[idx];
  98        u32 __iomem *crc_addr;
  99
 100        if (source == NV50_CRC_SOURCE_RG)
 101                crc_addr = &entry->rg_crc;
 102        else
 103                crc_addr = &entry->output_crc[0];
 104
 105        return ioread32_native(crc_addr);
 106}
 107
 108static bool crcc37d_ctx_finished(struct nv50_head *head,
 109                                 struct nv50_crc_notifier_ctx *ctx)
 110{
 111        struct nouveau_drm *drm = nouveau_drm(head->base.base.dev);
 112        struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
 113        const u32 status = ioread32_native(&notifier->status);
 114        const u32 overflow = status & 0x0000007e;
 115
 116        if (!(status & 0x00000001))
 117                return false;
 118
 119        if (overflow) {
 120                const char *engine = NULL;
 121
 122                switch (overflow) {
 123                case 0x00000004: engine = "Front End"; break;
 124                case 0x00000008: engine = "Compositor"; break;
 125                case 0x00000010: engine = "RG"; break;
 126                case 0x00000020: engine = "CRC output 1"; break;
 127                case 0x00000040: engine = "CRC output 2"; break;
 128                }
 129
 130                if (engine)
 131                        NV_ERROR(drm,
 132                                 "CRC notifier context for head %d overflowed on %s: %x\n",
 133                                 head->base.index, engine, status);
 134                else
 135                        NV_ERROR(drm,
 136                                 "CRC notifier context for head %d overflowed: %x\n",
 137                                 head->base.index, status);
 138        }
 139
 140        NV_DEBUG(drm, "Head %d CRC context status: %x\n",
 141                 head->base.index, status);
 142
 143        return true;
 144}
 145
 146const struct nv50_crc_func crcc37d = {
 147        .set_src = crcc37d_set_src,
 148        .set_ctx = crcc37d_set_ctx,
 149        .get_entry = crcc37d_get_entry,
 150        .ctx_finished = crcc37d_ctx_finished,
 151        .flip_threshold = CRCC37D_MAX_ENTRIES - 30,
 152        .num_entries = CRCC37D_MAX_ENTRIES,
 153        .notifier_len = sizeof(struct crcc37d_notifier),
 154};
 155