1 // SPDX-License-Identifier: MIT
2 #include <drm/drm_crtc.h>
9 #include <nvif/push507c.h>
11 #include <nvhw/class/cl907d.h>
13 #define CRC907D_MAX_ENTRIES 255
15 struct crc907d_notifier
{
17 u32
:32; /* reserved */
18 struct crc907d_entry
{
22 } entries
[CRC907D_MAX_ENTRIES
];
26 crc907d_set_src(struct nv50_head
*head
, int or,
27 enum nv50_crc_source_type source
,
28 struct nv50_crc_notifier_ctx
*ctx
, u32 wndw
)
30 struct nvif_push
*push
= nv50_disp(head
->base
.base
.dev
)->core
->chan
.push
;
31 const int i
= head
->base
.index
;
32 u32 crc_args
= NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, CONTROLLING_CHANNEL
, CORE
) |
33 NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, EXPECT_BUFFER_COLLAPSE
, FALSE
) |
34 NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, TIMESTAMP_MODE
, FALSE
) |
35 NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, SECONDARY_OUTPUT
, NONE
) |
36 NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, CRC_DURING_SNOOZE
, DISABLE
);
40 case NV50_CRC_SOURCE_TYPE_SOR
:
41 crc_args
|= NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, PRIMARY_OUTPUT
, SOR(or));
43 case NV50_CRC_SOURCE_TYPE_PIOR
:
44 crc_args
|= NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, PRIMARY_OUTPUT
, PIOR(or));
46 case NV50_CRC_SOURCE_TYPE_DAC
:
47 crc_args
|= NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, PRIMARY_OUTPUT
, DAC(or));
49 case NV50_CRC_SOURCE_TYPE_RG
:
50 crc_args
|= NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, PRIMARY_OUTPUT
, RG(i
));
52 case NV50_CRC_SOURCE_TYPE_SF
:
53 crc_args
|= NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, PRIMARY_OUTPUT
, SF(i
));
55 case NV50_CRC_SOURCE_NONE
:
56 crc_args
|= NVDEF(NV907D
, HEAD_SET_CRC_CONTROL
, PRIMARY_OUTPUT
, NONE
);
60 if ((ret
= PUSH_WAIT(push
, 4)))
64 PUSH_MTHD(push
, NV907D
, HEAD_SET_CONTEXT_DMA_CRC(i
), ctx
->ntfy
.handle
);
65 PUSH_MTHD(push
, NV907D
, HEAD_SET_CRC_CONTROL(i
), crc_args
);
67 PUSH_MTHD(push
, NV907D
, HEAD_SET_CRC_CONTROL(i
), crc_args
);
68 PUSH_MTHD(push
, NV907D
, HEAD_SET_CONTEXT_DMA_CRC(i
), 0);
75 crc907d_set_ctx(struct nv50_head
*head
, struct nv50_crc_notifier_ctx
*ctx
)
77 struct nvif_push
*push
= nv50_disp(head
->base
.base
.dev
)->core
->chan
.push
;
78 const int i
= head
->base
.index
;
81 if ((ret
= PUSH_WAIT(push
, 2)))
84 PUSH_MTHD(push
, NV907D
, HEAD_SET_CONTEXT_DMA_CRC(i
), ctx
? ctx
->ntfy
.handle
: 0);
88 static u32
crc907d_get_entry(struct nv50_head
*head
,
89 struct nv50_crc_notifier_ctx
*ctx
,
90 enum nv50_crc_source source
, int idx
)
92 struct crc907d_notifier __iomem
*notifier
= ctx
->mem
.object
.map
.ptr
;
94 return ioread32_native(¬ifier
->entries
[idx
].output_crc
[0]);
97 static bool crc907d_ctx_finished(struct nv50_head
*head
,
98 struct nv50_crc_notifier_ctx
*ctx
)
100 struct nouveau_drm
*drm
= nouveau_drm(head
->base
.base
.dev
);
101 struct crc907d_notifier __iomem
*notifier
= ctx
->mem
.object
.map
.ptr
;
102 const u32 status
= ioread32_native(¬ifier
->status
);
103 const u32 overflow
= status
& 0x0000003e;
105 if (!(status
& 0x00000001))
109 const char *engine
= NULL
;
112 case 0x00000004: engine
= "DSI"; break;
113 case 0x00000008: engine
= "Compositor"; break;
114 case 0x00000010: engine
= "CRC output 1"; break;
115 case 0x00000020: engine
= "CRC output 2"; break;
120 "CRC notifier context for head %d overflowed on %s: %x\n",
121 head
->base
.index
, engine
, status
);
124 "CRC notifier context for head %d overflowed: %x\n",
125 head
->base
.index
, status
);
128 NV_DEBUG(drm
, "Head %d CRC context status: %x\n",
129 head
->base
.index
, status
);
134 const struct nv50_crc_func crc907d
= {
135 .set_src
= crc907d_set_src
,
136 .set_ctx
= crc907d_set_ctx
,
137 .get_entry
= crc907d_get_entry
,
138 .ctx_finished
= crc907d_ctx_finished
,
139 .flip_threshold
= CRC907D_MAX_ENTRIES
- 10,
140 .num_entries
= CRC907D_MAX_ENTRIES
,
141 .notifier_len
= sizeof(struct crc907d_notifier
),