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 15 struct 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 25 static int 26 crc907d_set_src(struct nv50_head *head, int or, enum nv50_crc_source_type source, 27 struct nv50_crc_notifier_ctx *ctx) 28 { 29 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; 30 const int i = head->base.index; 31 u32 crc_args = NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, CORE) | 32 NVDEF(NV907D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) | 33 NVDEF(NV907D, HEAD_SET_CRC_CONTROL, TIMESTAMP_MODE, FALSE) | 34 NVDEF(NV907D, HEAD_SET_CRC_CONTROL, SECONDARY_OUTPUT, NONE) | 35 NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE) | 36 NVDEF(NV907D, HEAD_SET_CRC_CONTROL, WIDE_PIPE_CRC, ENABLE); 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 74 static int 75 crc907d_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 88 static 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(¬ifier->entries[idx].output_crc[0]); 95 } 96 97 static 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(¬ifier->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 134 const 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