Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 #include <drm/drm_crtc.h>
0003 
0004 #include "crc.h"
0005 #include "core.h"
0006 #include "disp.h"
0007 #include "head.h"
0008 
0009 #include <nvif/push507c.h>
0010 
0011 #include <nvhw/class/cl907d.h>
0012 
0013 #define CRC907D_MAX_ENTRIES 255
0014 
0015 struct crc907d_notifier {
0016     u32 status;
0017     u32 :32; /* reserved */
0018     struct crc907d_entry {
0019         u32 status;
0020         u32 compositor_crc;
0021         u32 output_crc[2];
0022     } entries[CRC907D_MAX_ENTRIES];
0023 } __packed;
0024 
0025 static int
0026 crc907d_set_src(struct nv50_head *head, int or, enum nv50_crc_source_type source,
0027         struct nv50_crc_notifier_ctx *ctx)
0028 {
0029     struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0030     const int i = head->base.index;
0031     u32 crc_args = NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, CORE) |
0032                NVDEF(NV907D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) |
0033                NVDEF(NV907D, HEAD_SET_CRC_CONTROL, TIMESTAMP_MODE, FALSE) |
0034                NVDEF(NV907D, HEAD_SET_CRC_CONTROL, SECONDARY_OUTPUT, NONE) |
0035                NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE) |
0036                NVDEF(NV907D, HEAD_SET_CRC_CONTROL, WIDE_PIPE_CRC, ENABLE);
0037     int ret;
0038 
0039     switch (source) {
0040     case NV50_CRC_SOURCE_TYPE_SOR:
0041         crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, SOR(or));
0042         break;
0043     case NV50_CRC_SOURCE_TYPE_PIOR:
0044         crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, PIOR(or));
0045         break;
0046     case NV50_CRC_SOURCE_TYPE_DAC:
0047         crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, DAC(or));
0048         break;
0049     case NV50_CRC_SOURCE_TYPE_RG:
0050         crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, RG(i));
0051         break;
0052     case NV50_CRC_SOURCE_TYPE_SF:
0053         crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, SF(i));
0054         break;
0055     case NV50_CRC_SOURCE_NONE:
0056         crc_args |= NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, NONE);
0057         break;
0058     }
0059 
0060     if ((ret = PUSH_WAIT(push, 4)))
0061         return ret;
0062 
0063     if (source) {
0064         PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx->ntfy.handle);
0065         PUSH_MTHD(push, NV907D, HEAD_SET_CRC_CONTROL(i), crc_args);
0066     } else {
0067         PUSH_MTHD(push, NV907D, HEAD_SET_CRC_CONTROL(i), crc_args);
0068         PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CRC(i), 0);
0069     }
0070 
0071     return 0;
0072 }
0073 
0074 static int
0075 crc907d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx)
0076 {
0077     struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
0078     const int i = head->base.index;
0079     int ret;
0080 
0081     if ((ret = PUSH_WAIT(push, 2)))
0082         return ret;
0083 
0084     PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx ? ctx->ntfy.handle : 0);
0085     return 0;
0086 }
0087 
0088 static u32 crc907d_get_entry(struct nv50_head *head,
0089                  struct nv50_crc_notifier_ctx *ctx,
0090                  enum nv50_crc_source source, int idx)
0091 {
0092     struct crc907d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
0093 
0094     return ioread32_native(&notifier->entries[idx].output_crc[0]);
0095 }
0096 
0097 static bool crc907d_ctx_finished(struct nv50_head *head,
0098                  struct nv50_crc_notifier_ctx *ctx)
0099 {
0100     struct nouveau_drm *drm = nouveau_drm(head->base.base.dev);
0101     struct crc907d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
0102     const u32 status = ioread32_native(&notifier->status);
0103     const u32 overflow = status & 0x0000003e;
0104 
0105     if (!(status & 0x00000001))
0106         return false;
0107 
0108     if (overflow) {
0109         const char *engine = NULL;
0110 
0111         switch (overflow) {
0112         case 0x00000004: engine = "DSI"; break;
0113         case 0x00000008: engine = "Compositor"; break;
0114         case 0x00000010: engine = "CRC output 1"; break;
0115         case 0x00000020: engine = "CRC output 2"; break;
0116         }
0117 
0118         if (engine)
0119             NV_ERROR(drm,
0120                  "CRC notifier context for head %d overflowed on %s: %x\n",
0121                  head->base.index, engine, status);
0122         else
0123             NV_ERROR(drm,
0124                  "CRC notifier context for head %d overflowed: %x\n",
0125                  head->base.index, status);
0126     }
0127 
0128     NV_DEBUG(drm, "Head %d CRC context status: %x\n",
0129          head->base.index, status);
0130 
0131     return true;
0132 }
0133 
0134 const struct nv50_crc_func crc907d = {
0135     .set_src = crc907d_set_src,
0136     .set_ctx = crc907d_set_ctx,
0137     .get_entry = crc907d_get_entry,
0138     .ctx_finished = crc907d_ctx_finished,
0139     .flip_threshold = CRC907D_MAX_ENTRIES - 10,
0140     .num_entries = CRC907D_MAX_ENTRIES,
0141     .notifier_len = sizeof(struct crc907d_notifier),
0142 };