1 // SPDX-License-Identifier: MIT
2 #include <drm/drm_crtc.h>
9 #include <nvif/pushc37b.h>
11 #include <nvhw/class/clc37d.h>
13 #define CRCC37D_MAX_ENTRIES 2047
15 struct crcc37d_notifier
{
27 struct crcc37d_entry
{
29 u32
:32; /* reserved */
33 u32
:32; /* reserved */
34 } entries
[CRCC37D_MAX_ENTRIES
];
38 crcc37d_set_src(struct nv50_head
*head
, int or,
39 enum nv50_crc_source_type source
,
40 struct nv50_crc_notifier_ctx
*ctx
, u32 wndw
)
42 struct nvif_push
*push
= nv50_disp(head
->base
.base
.dev
)->core
->chan
.push
;
43 const int i
= head
->base
.index
;
44 u32 crc_args
= NVVAL(NVC37D
, HEAD_SET_CRC_CONTROL
, CONTROLLING_CHANNEL
, wndw
) |
45 NVDEF(NVC37D
, HEAD_SET_CRC_CONTROL
, EXPECT_BUFFER_COLLAPSE
, FALSE
) |
46 NVDEF(NVC37D
, HEAD_SET_CRC_CONTROL
, SECONDARY_CRC
, NONE
) |
47 NVDEF(NVC37D
, HEAD_SET_CRC_CONTROL
, CRC_DURING_SNOOZE
, DISABLE
);
51 case NV50_CRC_SOURCE_TYPE_SOR
:
52 crc_args
|= NVDEF(NVC37D
, HEAD_SET_CRC_CONTROL
, PRIMARY_CRC
, SOR(or));
54 case NV50_CRC_SOURCE_TYPE_PIOR
:
55 crc_args
|= NVDEF(NVC37D
, HEAD_SET_CRC_CONTROL
, PRIMARY_CRC
, PIOR(or));
57 case NV50_CRC_SOURCE_TYPE_SF
:
58 crc_args
|= NVDEF(NVC37D
, HEAD_SET_CRC_CONTROL
, PRIMARY_CRC
, SF
);
64 if ((ret
= PUSH_WAIT(push
, 4)))
68 PUSH_MTHD(push
, NVC37D
, HEAD_SET_CONTEXT_DMA_CRC(i
), ctx
->ntfy
.handle
);
69 PUSH_MTHD(push
, NVC37D
, HEAD_SET_CRC_CONTROL(i
), crc_args
);
71 PUSH_MTHD(push
, NVC37D
, HEAD_SET_CRC_CONTROL(i
), 0);
72 PUSH_MTHD(push
, NVC37D
, HEAD_SET_CONTEXT_DMA_CRC(i
), 0);
79 crcc37d_set_ctx(struct nv50_head
*head
, struct nv50_crc_notifier_ctx
*ctx
)
81 struct nvif_push
*push
= nv50_disp(head
->base
.base
.dev
)->core
->chan
.push
;
82 const int i
= head
->base
.index
;
85 if ((ret
= PUSH_WAIT(push
, 2)))
88 PUSH_MTHD(push
, NVC37D
, HEAD_SET_CONTEXT_DMA_CRC(i
), ctx
? ctx
->ntfy
.handle
: 0);
92 static u32
crcc37d_get_entry(struct nv50_head
*head
,
93 struct nv50_crc_notifier_ctx
*ctx
,
94 enum nv50_crc_source source
, int idx
)
96 struct crcc37d_notifier __iomem
*notifier
= ctx
->mem
.object
.map
.ptr
;
97 struct crcc37d_entry __iomem
*entry
= ¬ifier
->entries
[idx
];
98 u32 __iomem
*crc_addr
;
100 if (source
== NV50_CRC_SOURCE_RG
)
101 crc_addr
= &entry
->rg_crc
;
103 crc_addr
= &entry
->output_crc
[0];
105 return ioread32_native(crc_addr
);
108 static bool crcc37d_ctx_finished(struct nv50_head
*head
,
109 struct nv50_crc_notifier_ctx
*ctx
)
111 struct nouveau_drm
*drm
= nouveau_drm(head
->base
.base
.dev
);
112 struct crcc37d_notifier __iomem
*notifier
= ctx
->mem
.object
.map
.ptr
;
113 const u32 status
= ioread32_native(¬ifier
->status
);
114 const u32 overflow
= status
& 0x0000007e;
116 if (!(status
& 0x00000001))
120 const char *engine
= NULL
;
123 case 0x00000004: engine
= "Front End"; break;
124 case 0x00000008: engine
= "Compositor"; break;
125 case 0x00000010: engine
= "RG"; break;
126 case 0x00000020: engine
= "CRC output 1"; break;
127 case 0x00000040: engine
= "CRC output 2"; break;
132 "CRC notifier context for head %d overflowed on %s: %x\n",
133 head
->base
.index
, engine
, status
);
136 "CRC notifier context for head %d overflowed: %x\n",
137 head
->base
.index
, status
);
140 NV_DEBUG(drm
, "Head %d CRC context status: %x\n",
141 head
->base
.index
, status
);
146 const struct nv50_crc_func crcc37d
= {
147 .set_src
= crcc37d_set_src
,
148 .set_ctx
= crcc37d_set_ctx
,
149 .get_entry
= crcc37d_get_entry
,
150 .ctx_finished
= crcc37d_ctx_finished
,
151 .flip_threshold
= CRCC37D_MAX_ENTRIES
- 30,
152 .num_entries
= CRCC37D_MAX_ENTRIES
,
153 .notifier_len
= sizeof(struct crcc37d_notifier
),