1 | /* |
2 | * Copyright 2018 Red Hat Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | */ |
22 | #include "core.h" |
23 | #include "head.h" |
24 | |
25 | #include <nvif/if0014.h> |
26 | #include <nvif/push507c.h> |
27 | #include <nvif/timer.h> |
28 | |
29 | #include <nvhw/class/cl507d.h> |
30 | |
31 | #include "nouveau_bo.h" |
32 | |
33 | int |
34 | core507d_update(struct nv50_core *core, u32 *interlock, bool ntfy) |
35 | { |
36 | struct nvif_push *push = core->chan.push; |
37 | int ret; |
38 | |
39 | if ((ret = PUSH_WAIT(push, (ntfy ? 2 : 0) + 3))) |
40 | return ret; |
41 | |
42 | if (ntfy) { |
43 | PUSH_MTHD(push, NV507D, SET_NOTIFIER_CONTROL, |
44 | NVDEF(NV507D, SET_NOTIFIER_CONTROL, MODE, WRITE) | |
45 | NVVAL(NV507D, SET_NOTIFIER_CONTROL, OFFSET, NV50_DISP_CORE_NTFY >> 2) | |
46 | NVDEF(NV507D, SET_NOTIFIER_CONTROL, NOTIFY, ENABLE)); |
47 | } |
48 | |
49 | PUSH_MTHD(push, NV507D, UPDATE, interlock[NV50_DISP_INTERLOCK_BASE] | |
50 | interlock[NV50_DISP_INTERLOCK_OVLY] | |
51 | NVDEF(NV507D, UPDATE, NOT_DRIVER_FRIENDLY, FALSE) | |
52 | NVDEF(NV507D, UPDATE, NOT_DRIVER_UNFRIENDLY, FALSE) | |
53 | NVDEF(NV507D, UPDATE, INHIBIT_INTERRUPTS, FALSE), |
54 | |
55 | SET_NOTIFIER_CONTROL, |
56 | NVDEF(NV507D, SET_NOTIFIER_CONTROL, NOTIFY, DISABLE)); |
57 | |
58 | return PUSH_KICK(push); |
59 | } |
60 | |
61 | int |
62 | core507d_ntfy_wait_done(struct nouveau_bo *bo, u32 offset, |
63 | struct nvif_device *device) |
64 | { |
65 | s64 time = nvif_msec(device, 2000ULL, |
66 | if (NVBO_TD32(bo, offset, NV_DISP_CORE_NOTIFIER_1, COMPLETION_0, DONE, ==, TRUE)) |
67 | break; |
68 | usleep_range(1, 2); |
69 | ); |
70 | return time < 0 ? time : 0; |
71 | } |
72 | |
73 | void |
74 | core507d_ntfy_init(struct nouveau_bo *bo, u32 offset) |
75 | { |
76 | NVBO_WR32(bo, offset, NV_DISP_CORE_NOTIFIER_1, COMPLETION_0, |
77 | NVDEF(NV_DISP_CORE_NOTIFIER_1, COMPLETION_0, DONE, FALSE)); |
78 | } |
79 | |
80 | int |
81 | core507d_read_caps(struct nv50_disp *disp) |
82 | { |
83 | struct nvif_push *push = disp->core->chan.push; |
84 | int ret; |
85 | |
86 | ret = PUSH_WAIT(push, 6); |
87 | if (ret) |
88 | return ret; |
89 | |
90 | PUSH_MTHD(push, NV507D, SET_NOTIFIER_CONTROL, |
91 | NVDEF(NV507D, SET_NOTIFIER_CONTROL, MODE, WRITE) | |
92 | NVVAL(NV507D, SET_NOTIFIER_CONTROL, OFFSET, NV50_DISP_CORE_NTFY >> 2) | |
93 | NVDEF(NV507D, SET_NOTIFIER_CONTROL, NOTIFY, ENABLE)); |
94 | |
95 | PUSH_MTHD(push, NV507D, GET_CAPABILITIES, 0x00000000); |
96 | |
97 | PUSH_MTHD(push, NV507D, SET_NOTIFIER_CONTROL, |
98 | NVDEF(NV507D, SET_NOTIFIER_CONTROL, NOTIFY, DISABLE)); |
99 | |
100 | return PUSH_KICK(push); |
101 | } |
102 | |
103 | int |
104 | core507d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp) |
105 | { |
106 | struct nv50_core *core = disp->core; |
107 | struct nouveau_bo *bo = disp->sync; |
108 | s64 time; |
109 | int ret; |
110 | |
111 | NVBO_WR32(bo, NV50_DISP_CORE_NTFY, NV_DISP_CORE_NOTIFIER_1, CAPABILITIES_1, |
112 | NVDEF(NV_DISP_CORE_NOTIFIER_1, CAPABILITIES_1, DONE, FALSE)); |
113 | |
114 | ret = core507d_read_caps(disp); |
115 | if (ret < 0) |
116 | return ret; |
117 | |
118 | time = nvif_msec(core->chan.base.device, 2000ULL, |
119 | if (NVBO_TD32(bo, NV50_DISP_CORE_NTFY, |
120 | NV_DISP_CORE_NOTIFIER_1, CAPABILITIES_1, DONE, ==, TRUE)) |
121 | break; |
122 | usleep_range(1, 2); |
123 | ); |
124 | if (time < 0) |
125 | NV_ERROR(drm, "core caps notifier timeout\n" ); |
126 | |
127 | return 0; |
128 | } |
129 | |
130 | int |
131 | core507d_init(struct nv50_core *core) |
132 | { |
133 | struct nvif_push *push = core->chan.push; |
134 | int ret; |
135 | |
136 | if ((ret = PUSH_WAIT(push, 2))) |
137 | return ret; |
138 | |
139 | PUSH_MTHD(push, NV507D, SET_CONTEXT_DMA_NOTIFIER, core->chan.sync.handle); |
140 | return PUSH_KICK(push); |
141 | } |
142 | |
143 | static const struct nv50_core_func |
144 | core507d = { |
145 | .init = core507d_init, |
146 | .ntfy_init = core507d_ntfy_init, |
147 | .caps_init = core507d_caps_init, |
148 | .ntfy_wait_done = core507d_ntfy_wait_done, |
149 | .update = core507d_update, |
150 | .head = &head507d, |
151 | .dac = &dac507d, |
152 | .sor = &sor507d, |
153 | .pior = &pior507d, |
154 | }; |
155 | |
156 | int |
157 | core507d_new_(const struct nv50_core_func *func, struct nouveau_drm *drm, |
158 | s32 oclass, struct nv50_core **pcore) |
159 | { |
160 | struct nvif_disp_chan_v0 args = {}; |
161 | struct nv50_disp *disp = nv50_disp(dev: drm->dev); |
162 | struct nv50_core *core; |
163 | int ret; |
164 | |
165 | if (!(core = *pcore = kzalloc(size: sizeof(*core), GFP_KERNEL))) |
166 | return -ENOMEM; |
167 | core->func = func; |
168 | |
169 | ret = nv50_dmac_create(device: &drm->client.device, disp: &disp->disp->object, |
170 | oclass: &oclass, head: 0, data: &args, size: sizeof(args), |
171 | syncbuf: disp->sync->offset, dmac: &core->chan); |
172 | if (ret) { |
173 | NV_ERROR(drm, "core%04x allocation failed: %d\n" , oclass, ret); |
174 | return ret; |
175 | } |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | int |
181 | core507d_new(struct nouveau_drm *drm, s32 oclass, struct nv50_core **pcore) |
182 | { |
183 | return core507d_new_(&core507d, drm, oclass, pcore); |
184 | } |
185 | |