xref: /linux/drivers/gpu/drm/nouveau/dispnv50/crc907d.c (revision 94cad89ae4505672ae65457d12f77c44ca87655b)
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(&notifier->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(&notifier->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