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