xref: /openbmc/linux/drivers/gpu/drm/nouveau/dispnv50/crcc37d.c (revision a255e9c8694d3ed240480d1b4d95d325a37358b3)
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*a255e9c8SLyude Paul #include <nvif/pushc37b.h>
10c4b27bc8SBen Skeggs 
116162638eSBen Skeggs #include <nvhw/class/clc37d.h>
126162638eSBen Skeggs 
1312885ecbSLyude Paul #define CRCC37D_MAX_ENTRIES 2047
1412885ecbSLyude Paul 
1512885ecbSLyude Paul struct crcc37d_notifier {
1612885ecbSLyude Paul 	u32 status;
1712885ecbSLyude Paul 
1812885ecbSLyude Paul 	/* reserved */
1912885ecbSLyude Paul 	u32 :32;
2012885ecbSLyude Paul 	u32 :32;
2112885ecbSLyude Paul 	u32 :32;
2212885ecbSLyude Paul 	u32 :32;
2312885ecbSLyude Paul 	u32 :32;
2412885ecbSLyude Paul 	u32 :32;
2512885ecbSLyude Paul 	u32 :32;
2612885ecbSLyude Paul 
2712885ecbSLyude Paul 	struct crcc37d_entry {
2812885ecbSLyude Paul 		u32 status[2];
2912885ecbSLyude Paul 		u32 :32; /* reserved */
3012885ecbSLyude Paul 		u32 compositor_crc;
3112885ecbSLyude Paul 		u32 rg_crc;
3212885ecbSLyude Paul 		u32 output_crc[2];
3312885ecbSLyude Paul 		u32 :32; /* reserved */
3412885ecbSLyude Paul 	} entries[CRCC37D_MAX_ENTRIES];
3512885ecbSLyude Paul } __packed;
3612885ecbSLyude Paul 
37c4b27bc8SBen Skeggs static int
3812885ecbSLyude Paul crcc37d_set_src(struct nv50_head *head, int or,
3912885ecbSLyude Paul 		enum nv50_crc_source_type source,
4012885ecbSLyude Paul 		struct nv50_crc_notifier_ctx *ctx, u32 wndw)
4112885ecbSLyude Paul {
42c4b27bc8SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
43c4b27bc8SBen Skeggs 	const int i = head->base.index;
446162638eSBen Skeggs 	u32 crc_args = NVVAL(NVC37D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, wndw) |
456162638eSBen Skeggs 		       NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) |
466162638eSBen Skeggs 		       NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, SECONDARY_CRC, NONE) |
476162638eSBen Skeggs 		       NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE);
48c4b27bc8SBen Skeggs 	int ret;
4912885ecbSLyude Paul 
5012885ecbSLyude Paul 	switch (source) {
5112885ecbSLyude Paul 	case NV50_CRC_SOURCE_TYPE_SOR:
526162638eSBen Skeggs 		crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SOR(or));
5312885ecbSLyude Paul 		break;
5412885ecbSLyude Paul 	case NV50_CRC_SOURCE_TYPE_PIOR:
556162638eSBen Skeggs 		crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, PIOR(or));
5612885ecbSLyude Paul 		break;
5712885ecbSLyude Paul 	case NV50_CRC_SOURCE_TYPE_SF:
586162638eSBen Skeggs 		crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SF);
5912885ecbSLyude Paul 		break;
6012885ecbSLyude Paul 	default:
6112885ecbSLyude Paul 		break;
6212885ecbSLyude Paul 	}
6312885ecbSLyude Paul 
64c4b27bc8SBen Skeggs 	if ((ret = PUSH_WAIT(push, 4)))
65c4b27bc8SBen Skeggs 		return ret;
6612885ecbSLyude Paul 
6712885ecbSLyude Paul 	if (source) {
686162638eSBen Skeggs 		PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx->ntfy.handle);
696162638eSBen Skeggs 		PUSH_MTHD(push, NVC37D, HEAD_SET_CRC_CONTROL(i), crc_args);
7012885ecbSLyude Paul 	} else {
716162638eSBen Skeggs 		PUSH_MTHD(push, NVC37D, HEAD_SET_CRC_CONTROL(i), 0);
726162638eSBen Skeggs 		PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), 0);
7312885ecbSLyude Paul 	}
7412885ecbSLyude Paul 
75c4b27bc8SBen Skeggs 	return 0;
7612885ecbSLyude Paul }
7712885ecbSLyude Paul 
78ae09163aSBen Skeggs static int
79ae09163aSBen Skeggs crcc37d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx)
8012885ecbSLyude Paul {
81ae09163aSBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
82ae09163aSBen Skeggs 	const int i = head->base.index;
83ae09163aSBen Skeggs 	int ret;
8412885ecbSLyude Paul 
85ae09163aSBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
86ae09163aSBen Skeggs 		return ret;
8712885ecbSLyude Paul 
881fad04ceSBen Skeggs 	PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx ? ctx->ntfy.handle : 0);
89ae09163aSBen Skeggs 	return 0;
9012885ecbSLyude Paul }
9112885ecbSLyude Paul 
9212885ecbSLyude Paul static u32 crcc37d_get_entry(struct nv50_head *head,
9312885ecbSLyude Paul 			     struct nv50_crc_notifier_ctx *ctx,
9412885ecbSLyude Paul 			     enum nv50_crc_source source, int idx)
9512885ecbSLyude Paul {
9612885ecbSLyude Paul 	struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
9712885ecbSLyude Paul 	struct crcc37d_entry __iomem *entry = &notifier->entries[idx];
9812885ecbSLyude Paul 	u32 __iomem *crc_addr;
9912885ecbSLyude Paul 
10012885ecbSLyude Paul 	if (source == NV50_CRC_SOURCE_RG)
10112885ecbSLyude Paul 		crc_addr = &entry->rg_crc;
10212885ecbSLyude Paul 	else
10312885ecbSLyude Paul 		crc_addr = &entry->output_crc[0];
10412885ecbSLyude Paul 
10512885ecbSLyude Paul 	return ioread32_native(crc_addr);
10612885ecbSLyude Paul }
10712885ecbSLyude Paul 
10812885ecbSLyude Paul static bool crcc37d_ctx_finished(struct nv50_head *head,
10912885ecbSLyude Paul 				 struct nv50_crc_notifier_ctx *ctx)
11012885ecbSLyude Paul {
11112885ecbSLyude Paul 	struct nouveau_drm *drm = nouveau_drm(head->base.base.dev);
11212885ecbSLyude Paul 	struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr;
11312885ecbSLyude Paul 	const u32 status = ioread32_native(&notifier->status);
11412885ecbSLyude Paul 	const u32 overflow = status & 0x0000007e;
11512885ecbSLyude Paul 
11612885ecbSLyude Paul 	if (!(status & 0x00000001))
11712885ecbSLyude Paul 		return false;
11812885ecbSLyude Paul 
11912885ecbSLyude Paul 	if (overflow) {
12012885ecbSLyude Paul 		const char *engine = NULL;
12112885ecbSLyude Paul 
12212885ecbSLyude Paul 		switch (overflow) {
12312885ecbSLyude Paul 		case 0x00000004: engine = "Front End"; break;
12412885ecbSLyude Paul 		case 0x00000008: engine = "Compositor"; break;
12512885ecbSLyude Paul 		case 0x00000010: engine = "RG"; break;
12612885ecbSLyude Paul 		case 0x00000020: engine = "CRC output 1"; break;
12712885ecbSLyude Paul 		case 0x00000040: engine = "CRC output 2"; break;
12812885ecbSLyude Paul 		}
12912885ecbSLyude Paul 
13012885ecbSLyude Paul 		if (engine)
13112885ecbSLyude Paul 			NV_ERROR(drm,
13212885ecbSLyude Paul 				 "CRC notifier context for head %d overflowed on %s: %x\n",
13312885ecbSLyude Paul 				 head->base.index, engine, status);
13412885ecbSLyude Paul 		else
13512885ecbSLyude Paul 			NV_ERROR(drm,
13612885ecbSLyude Paul 				 "CRC notifier context for head %d overflowed: %x\n",
13712885ecbSLyude Paul 				 head->base.index, status);
13812885ecbSLyude Paul 	}
13912885ecbSLyude Paul 
14012885ecbSLyude Paul 	NV_DEBUG(drm, "Head %d CRC context status: %x\n",
14112885ecbSLyude Paul 		 head->base.index, status);
14212885ecbSLyude Paul 
14312885ecbSLyude Paul 	return true;
14412885ecbSLyude Paul }
14512885ecbSLyude Paul 
14612885ecbSLyude Paul const struct nv50_crc_func crcc37d = {
14712885ecbSLyude Paul 	.set_src = crcc37d_set_src,
14812885ecbSLyude Paul 	.set_ctx = crcc37d_set_ctx,
14912885ecbSLyude Paul 	.get_entry = crcc37d_get_entry,
15012885ecbSLyude Paul 	.ctx_finished = crcc37d_ctx_finished,
15112885ecbSLyude Paul 	.flip_threshold = CRCC37D_MAX_ENTRIES - 30,
15212885ecbSLyude Paul 	.num_entries = CRCC37D_MAX_ENTRIES,
15312885ecbSLyude Paul 	.notifier_len = sizeof(struct crcc37d_notifier),
15412885ecbSLyude Paul };
155