1 | // SPDX-License-Identifier: MIT |
2 | #include <drm/drm_crtc.h> |
3 | |
4 | #include "crc.h" |
5 | #include "crcc37d.h" |
6 | #include "core.h" |
7 | #include "disp.h" |
8 | #include "head.h" |
9 | |
10 | #include <nvif/pushc37b.h> |
11 | |
12 | #include <nvhw/class/clc37d.h> |
13 | |
14 | static int |
15 | crcc37d_set_src(struct nv50_head *head, int or, enum nv50_crc_source_type source, |
16 | struct nv50_crc_notifier_ctx *ctx) |
17 | { |
18 | struct nvif_push *push = nv50_disp(dev: head->base.base.dev)->core->chan.push; |
19 | const int i = head->base.index; |
20 | u32 crc_args = NVVAL(NVC37D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, i * 4) | |
21 | NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) | |
22 | NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, SECONDARY_CRC, NONE) | |
23 | NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE); |
24 | int ret; |
25 | |
26 | switch (source) { |
27 | case NV50_CRC_SOURCE_TYPE_SOR: |
28 | crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SOR(or)); |
29 | break; |
30 | case NV50_CRC_SOURCE_TYPE_PIOR: |
31 | crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, PIOR(or)); |
32 | break; |
33 | case NV50_CRC_SOURCE_TYPE_SF: |
34 | crc_args |= NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SF); |
35 | break; |
36 | default: |
37 | break; |
38 | } |
39 | |
40 | if ((ret = PUSH_WAIT(push, 4))) |
41 | return ret; |
42 | |
43 | if (source) { |
44 | PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx->ntfy.handle); |
45 | PUSH_MTHD(push, NVC37D, HEAD_SET_CRC_CONTROL(i), crc_args); |
46 | } else { |
47 | PUSH_MTHD(push, NVC37D, HEAD_SET_CRC_CONTROL(i), 0); |
48 | PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), 0); |
49 | } |
50 | |
51 | return 0; |
52 | } |
53 | |
54 | int crcc37d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx) |
55 | { |
56 | struct nvif_push *push = nv50_disp(dev: head->base.base.dev)->core->chan.push; |
57 | const int i = head->base.index; |
58 | int ret; |
59 | |
60 | if ((ret = PUSH_WAIT(push, 2))) |
61 | return ret; |
62 | |
63 | PUSH_MTHD(push, NVC37D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx ? ctx->ntfy.handle : 0); |
64 | return 0; |
65 | } |
66 | |
67 | u32 crcc37d_get_entry(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx, |
68 | enum nv50_crc_source source, int idx) |
69 | { |
70 | struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr; |
71 | struct crcc37d_entry __iomem *entry = ¬ifier->entries[idx]; |
72 | u32 __iomem *crc_addr; |
73 | |
74 | if (source == NV50_CRC_SOURCE_RG) |
75 | crc_addr = &entry->rg_crc; |
76 | else |
77 | crc_addr = &entry->output_crc[0]; |
78 | |
79 | return ioread32_native(crc_addr); |
80 | } |
81 | |
82 | bool crcc37d_ctx_finished(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx) |
83 | { |
84 | struct nouveau_drm *drm = nouveau_drm(head->base.base.dev); |
85 | struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr; |
86 | const u32 status = ioread32_native(¬ifier->status); |
87 | const u32 overflow = status & 0x0000007e; |
88 | |
89 | if (!(status & 0x00000001)) |
90 | return false; |
91 | |
92 | if (overflow) { |
93 | const char *engine = NULL; |
94 | |
95 | switch (overflow) { |
96 | case 0x00000004: engine = "Front End" ; break; |
97 | case 0x00000008: engine = "Compositor" ; break; |
98 | case 0x00000010: engine = "RG" ; break; |
99 | case 0x00000020: engine = "CRC output 1" ; break; |
100 | case 0x00000040: engine = "CRC output 2" ; break; |
101 | } |
102 | |
103 | if (engine) |
104 | NV_ERROR(drm, |
105 | "CRC notifier context for head %d overflowed on %s: %x\n" , |
106 | head->base.index, engine, status); |
107 | else |
108 | NV_ERROR(drm, |
109 | "CRC notifier context for head %d overflowed: %x\n" , |
110 | head->base.index, status); |
111 | } |
112 | |
113 | NV_DEBUG(drm, "Head %d CRC context status: %x\n" , |
114 | head->base.index, status); |
115 | |
116 | return true; |
117 | } |
118 | |
119 | const struct nv50_crc_func crcc37d = { |
120 | .set_src = crcc37d_set_src, |
121 | .set_ctx = crcc37d_set_ctx, |
122 | .get_entry = crcc37d_get_entry, |
123 | .ctx_finished = crcc37d_ctx_finished, |
124 | .flip_threshold = CRCC37D_FLIP_THRESHOLD, |
125 | .num_entries = CRCC37D_MAX_ENTRIES, |
126 | .notifier_len = sizeof(struct crcc37d_notifier), |
127 | }; |
128 | |