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