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 #define CRC907D_MAX_ENTRIES 255 10 11 struct crc907d_notifier { 12 u32 status; 13 u32 :32; /* reserved */ 14 struct crc907d_entry { 15 u32 status; 16 u32 compositor_crc; 17 u32 output_crc[2]; 18 } entries[CRC907D_MAX_ENTRIES]; 19 } __packed; 20 21 static void 22 crc907d_set_src(struct nv50_head *head, int or, 23 enum nv50_crc_source_type source, 24 struct nv50_crc_notifier_ctx *ctx, u32 wndw) 25 { 26 struct drm_crtc *crtc = &head->base.base; 27 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 28 const u32 hoff = head->base.index * 0x300; 29 u32 *push; 30 u32 crc_args = 0xfff00000; 31 32 switch (source) { 33 case NV50_CRC_SOURCE_TYPE_SOR: 34 crc_args |= (0x00000f0f + or * 16) << 8; 35 break; 36 case NV50_CRC_SOURCE_TYPE_PIOR: 37 crc_args |= (0x000000ff + or * 256) << 8; 38 break; 39 case NV50_CRC_SOURCE_TYPE_DAC: 40 crc_args |= (0x00000ff0 + or) << 8; 41 break; 42 case NV50_CRC_SOURCE_TYPE_RG: 43 crc_args |= (0x00000ff8 + drm_crtc_index(crtc)) << 8; 44 break; 45 case NV50_CRC_SOURCE_TYPE_SF: 46 crc_args |= (0x00000f8f + drm_crtc_index(crtc) * 16) << 8; 47 break; 48 case NV50_CRC_SOURCE_NONE: 49 crc_args |= 0x000fff00; 50 break; 51 } 52 53 push = evo_wait(core, 4); 54 if (!push) 55 return; 56 57 if (source) { 58 evo_mthd(push, 0x0438 + hoff, 1); 59 evo_data(push, ctx->ntfy.handle); 60 evo_mthd(push, 0x0430 + hoff, 1); 61 evo_data(push, crc_args); 62 } else { 63 evo_mthd(push, 0x0430 + hoff, 1); 64 evo_data(push, crc_args); 65 evo_mthd(push, 0x0438 + hoff, 1); 66 evo_data(push, 0); 67 } 68 evo_kick(push, core); 69 } 70 71 static void crc907d_set_ctx(struct nv50_head *head, 72 struct nv50_crc_notifier_ctx *ctx) 73 { 74 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan; 75 u32 *push = evo_wait(core, 2); 76 77 if (!push) 78 return; 79 80 evo_mthd(push, 0x0438 + (head->base.index * 0x300), 1); 81 evo_data(push, ctx ? ctx->ntfy.handle : 0); 82 evo_kick(push, core); 83 } 84 85 static u32 crc907d_get_entry(struct nv50_head *head, 86 struct nv50_crc_notifier_ctx *ctx, 87 enum nv50_crc_source source, int idx) 88 { 89 struct crc907d_notifier __iomem *notifier = ctx->mem.object.map.ptr; 90 91 return ioread32_native(¬ifier->entries[idx].output_crc[0]); 92 } 93 94 static bool crc907d_ctx_finished(struct nv50_head *head, 95 struct nv50_crc_notifier_ctx *ctx) 96 { 97 struct nouveau_drm *drm = nouveau_drm(head->base.base.dev); 98 struct crc907d_notifier __iomem *notifier = ctx->mem.object.map.ptr; 99 const u32 status = ioread32_native(¬ifier->status); 100 const u32 overflow = status & 0x0000003e; 101 102 if (!(status & 0x00000001)) 103 return false; 104 105 if (overflow) { 106 const char *engine = NULL; 107 108 switch (overflow) { 109 case 0x00000004: engine = "DSI"; break; 110 case 0x00000008: engine = "Compositor"; break; 111 case 0x00000010: engine = "CRC output 1"; break; 112 case 0x00000020: engine = "CRC output 2"; break; 113 } 114 115 if (engine) 116 NV_ERROR(drm, 117 "CRC notifier context for head %d overflowed on %s: %x\n", 118 head->base.index, engine, status); 119 else 120 NV_ERROR(drm, 121 "CRC notifier context for head %d overflowed: %x\n", 122 head->base.index, status); 123 } 124 125 NV_DEBUG(drm, "Head %d CRC context status: %x\n", 126 head->base.index, status); 127 128 return true; 129 } 130 131 const struct nv50_crc_func crc907d = { 132 .set_src = crc907d_set_src, 133 .set_ctx = crc907d_set_ctx, 134 .get_entry = crc907d_get_entry, 135 .ctx_finished = crc907d_ctx_finished, 136 .flip_threshold = CRC907D_MAX_ENTRIES - 10, 137 .num_entries = CRC907D_MAX_ENTRIES, 138 .notifier_len = sizeof(struct crc907d_notifier), 139 }; 140