xref: /openbmc/linux/drivers/gpu/drm/nouveau/dispnv50/crcc37d.c (revision c4b27bc8682c5d919a7e95c7cb3e2021d8b37c92)
112885ecbSLyude Paul // SPDX-License-Identifier: MIT
212885ecbSLyude Paul #include <drm/drm_crtc.h>
312885ecbSLyude Paul 
412885ecbSLyude Paul #include "crc.h"
512885ecbSLyude Paul #include "core.h"
612885ecbSLyude Paul #include "disp.h"
712885ecbSLyude Paul #include "head.h"
812885ecbSLyude Paul 
9*c4b27bc8SBen Skeggs #include <nvif/push507c.h>
10*c4b27bc8SBen Skeggs 
1112885ecbSLyude Paul #define CRCC37D_MAX_ENTRIES 2047
1212885ecbSLyude Paul 
1312885ecbSLyude Paul struct crcc37d_notifier {
1412885ecbSLyude Paul 	u32 status;
1512885ecbSLyude Paul 
1612885ecbSLyude Paul 	/* reserved */
1712885ecbSLyude Paul 	u32 :32;
1812885ecbSLyude Paul 	u32 :32;
1912885ecbSLyude Paul 	u32 :32;
2012885ecbSLyude Paul 	u32 :32;
2112885ecbSLyude Paul 	u32 :32;
2212885ecbSLyude Paul 	u32 :32;
2312885ecbSLyude Paul 	u32 :32;
2412885ecbSLyude Paul 
2512885ecbSLyude Paul 	struct crcc37d_entry {
2612885ecbSLyude Paul 		u32 status[2];
2712885ecbSLyude Paul 		u32 :32; /* reserved */
2812885ecbSLyude Paul 		u32 compositor_crc;
2912885ecbSLyude Paul 		u32 rg_crc;
3012885ecbSLyude Paul 		u32 output_crc[2];
3112885ecbSLyude Paul 		u32 :32; /* reserved */
3212885ecbSLyude Paul 	} entries[CRCC37D_MAX_ENTRIES];
3312885ecbSLyude Paul } __packed;
3412885ecbSLyude Paul 
35*c4b27bc8SBen Skeggs static int
3612885ecbSLyude Paul crcc37d_set_src(struct nv50_head *head, int or,
3712885ecbSLyude Paul 		enum nv50_crc_source_type source,
3812885ecbSLyude Paul 		struct nv50_crc_notifier_ctx *ctx, u32 wndw)
3912885ecbSLyude Paul {
40*c4b27bc8SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
41*c4b27bc8SBen Skeggs 	const int i = head->base.index;
4212885ecbSLyude Paul 	u32 crc_args;
43*c4b27bc8SBen Skeggs 	int ret;
4412885ecbSLyude Paul 
4512885ecbSLyude Paul 	switch (source) {
4612885ecbSLyude Paul 	case NV50_CRC_SOURCE_TYPE_SOR:
4712885ecbSLyude Paul 		crc_args = (0x00000050 + or) << 12;
4812885ecbSLyude Paul 		break;
4912885ecbSLyude Paul 	case NV50_CRC_SOURCE_TYPE_PIOR:
5012885ecbSLyude Paul 		crc_args = (0x00000060 + or) << 12;
5112885ecbSLyude Paul 		break;
5212885ecbSLyude Paul 	case NV50_CRC_SOURCE_TYPE_SF:
5312885ecbSLyude Paul 		crc_args = 0x00000030 << 12;
5412885ecbSLyude Paul 		break;
5512885ecbSLyude Paul 	default:
5612885ecbSLyude Paul 		crc_args = 0;
5712885ecbSLyude Paul 		break;
5812885ecbSLyude Paul 	}
5912885ecbSLyude Paul 
60*c4b27bc8SBen Skeggs 	if ((ret = PUSH_WAIT(push, 4)))
61*c4b27bc8SBen Skeggs 		return ret;
6212885ecbSLyude Paul 
6312885ecbSLyude Paul 	if (source) {
64*c4b27bc8SBen Skeggs 		PUSH_NVSQ(push, NVC37D, 0x2180 + (i * 0x400), ctx->ntfy.handle);
65*c4b27bc8SBen Skeggs 		PUSH_NVSQ(push, NVC37D, 0x2184 + (i * 0x400), crc_args | wndw);
6612885ecbSLyude Paul 	} else {
67*c4b27bc8SBen Skeggs 		PUSH_NVSQ(push, NVC37D, 0x2184 + (i * 0x400), 0);
68*c4b27bc8SBen Skeggs 		PUSH_NVSQ(push, NVC37D, 0x2180 + (i * 0x400), 0);
6912885ecbSLyude Paul 	}
7012885ecbSLyude Paul 
71*c4b27bc8SBen Skeggs 	return 0;
7212885ecbSLyude Paul }
7312885ecbSLyude Paul 
7412885ecbSLyude Paul static void crcc37d_set_ctx(struct nv50_head *head,
7512885ecbSLyude Paul 			    struct nv50_crc_notifier_ctx *ctx)
7612885ecbSLyude Paul {
7712885ecbSLyude Paul 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
7812885ecbSLyude Paul 	u32 *push = evo_wait(core, 2);
7912885ecbSLyude Paul 
8012885ecbSLyude Paul 	if (!push)
8112885ecbSLyude Paul 		return;
8212885ecbSLyude Paul 
8312885ecbSLyude Paul 	evo_mthd(push, 0x2180 + (head->base.index * 0x400), 1);
8412885ecbSLyude Paul 	evo_data(push, ctx ? ctx->ntfy.handle : 0);
8512885ecbSLyude Paul 	evo_kick(push, core);
8612885ecbSLyude Paul }
8712885ecbSLyude Paul 
8812885ecbSLyude Paul static u32 crcc37d_get_entry(struct nv50_head *head,
8912885ecbSLyude Paul 			     struct nv50_crc_notifier_ctx *ctx,
9012885ecbSLyude Paul 			     enum nv50_crc_source source, int idx)
9112885ecbSLyude Paul {
9212885ecbSLyude Paul 	struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
9312885ecbSLyude Paul 	struct crcc37d_entry __iomem *entry = &notifier->entries[idx];
9412885ecbSLyude Paul 	u32 __iomem *crc_addr;
9512885ecbSLyude Paul 
9612885ecbSLyude Paul 	if (source == NV50_CRC_SOURCE_RG)
9712885ecbSLyude Paul 		crc_addr = &entry->rg_crc;
9812885ecbSLyude Paul 	else
9912885ecbSLyude Paul 		crc_addr = &entry->output_crc[0];
10012885ecbSLyude Paul 
10112885ecbSLyude Paul 	return ioread32_native(crc_addr);
10212885ecbSLyude Paul }
10312885ecbSLyude Paul 
10412885ecbSLyude Paul static bool crcc37d_ctx_finished(struct nv50_head *head,
10512885ecbSLyude Paul 				 struct nv50_crc_notifier_ctx *ctx)
10612885ecbSLyude Paul {
10712885ecbSLyude Paul 	struct nouveau_drm *drm = nouveau_drm(head->base.base.dev);
10812885ecbSLyude Paul 	struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
10912885ecbSLyude Paul 	const u32 status = ioread32_native(&notifier->status);
11012885ecbSLyude Paul 	const u32 overflow = status & 0x0000007e;
11112885ecbSLyude Paul 
11212885ecbSLyude Paul 	if (!(status & 0x00000001))
11312885ecbSLyude Paul 		return false;
11412885ecbSLyude Paul 
11512885ecbSLyude Paul 	if (overflow) {
11612885ecbSLyude Paul 		const char *engine = NULL;
11712885ecbSLyude Paul 
11812885ecbSLyude Paul 		switch (overflow) {
11912885ecbSLyude Paul 		case 0x00000004: engine = "Front End"; break;
12012885ecbSLyude Paul 		case 0x00000008: engine = "Compositor"; break;
12112885ecbSLyude Paul 		case 0x00000010: engine = "RG"; break;
12212885ecbSLyude Paul 		case 0x00000020: engine = "CRC output 1"; break;
12312885ecbSLyude Paul 		case 0x00000040: engine = "CRC output 2"; break;
12412885ecbSLyude Paul 		}
12512885ecbSLyude Paul 
12612885ecbSLyude Paul 		if (engine)
12712885ecbSLyude Paul 			NV_ERROR(drm,
12812885ecbSLyude Paul 				 "CRC notifier context for head %d overflowed on %s: %x\n",
12912885ecbSLyude Paul 				 head->base.index, engine, status);
13012885ecbSLyude Paul 		else
13112885ecbSLyude Paul 			NV_ERROR(drm,
13212885ecbSLyude Paul 				 "CRC notifier context for head %d overflowed: %x\n",
13312885ecbSLyude Paul 				 head->base.index, status);
13412885ecbSLyude Paul 	}
13512885ecbSLyude Paul 
13612885ecbSLyude Paul 	NV_DEBUG(drm, "Head %d CRC context status: %x\n",
13712885ecbSLyude Paul 		 head->base.index, status);
13812885ecbSLyude Paul 
13912885ecbSLyude Paul 	return true;
14012885ecbSLyude Paul }
14112885ecbSLyude Paul 
14212885ecbSLyude Paul const struct nv50_crc_func crcc37d = {
14312885ecbSLyude Paul 	.set_src = crcc37d_set_src,
14412885ecbSLyude Paul 	.set_ctx = crcc37d_set_ctx,
14512885ecbSLyude Paul 	.get_entry = crcc37d_get_entry,
14612885ecbSLyude Paul 	.ctx_finished = crcc37d_ctx_finished,
14712885ecbSLyude Paul 	.flip_threshold = CRCC37D_MAX_ENTRIES - 30,
14812885ecbSLyude Paul 	.num_entries = CRCC37D_MAX_ENTRIES,
14912885ecbSLyude Paul 	.notifier_len = sizeof(struct crcc37d_notifier),
15012885ecbSLyude Paul };
151