xref: /openbmc/linux/drivers/gpu/drm/nouveau/dispnv50/crcc37d.c (revision 12885ecbfe62df4358d452080d3b8feef54ec8cb)
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 = &notifier->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(&notifier->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