xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/nouveau/nvkm/engine/disp/nouveau_nvkm_engine_disp_rootnv50.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1 /*	$NetBSD: nouveau_nvkm_engine_disp_rootnv50.c,v 1.4 2021/12/18 23:45:35 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2012 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors: Ben Skeggs
25  */
26 #include <sys/cdefs.h>
27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_engine_disp_rootnv50.c,v 1.4 2021/12/18 23:45:35 riastradh Exp $");
28 
29 #include "rootnv50.h"
30 #include "channv50.h"
31 #include "dp.h"
32 #include "head.h"
33 #include "ior.h"
34 
35 #include <core/client.h>
36 
37 #include <nvif/class.h>
38 #include <nvif/cl5070.h>
39 #include <nvif/unpack.h>
40 
41 static int
nv50_disp_root_mthd_(struct nvkm_object * object,u32 mthd,void * data,u32 size)42 nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size)
43 {
44 	union {
45 		struct nv50_disp_mthd_v0 v0;
46 		struct nv50_disp_mthd_v1 v1;
47 	} *args = data;
48 	struct nv50_disp_root *root = nv50_disp_root(object);
49 	struct nv50_disp *disp = root->disp;
50 	struct nvkm_outp *temp, *outp = NULL;
51 	struct nvkm_head *head;
52 	u16 type, mask = 0;
53 	int hidx, ret = -ENOSYS;
54 
55 	if (mthd != NV50_DISP_MTHD)
56 		return -EINVAL;
57 
58 	nvif_ioctl(object, "disp mthd size %d\n", size);
59 	if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
60 		nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
61 			   args->v0.version, args->v0.method, args->v0.head);
62 		mthd = args->v0.method;
63 		hidx = args->v0.head;
64 	} else
65 	if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) {
66 		nvif_ioctl(object, "disp mthd vers %d mthd %02x "
67 				   "type %04x mask %04x\n",
68 			   args->v1.version, args->v1.method,
69 			   args->v1.hasht, args->v1.hashm);
70 		mthd = args->v1.method;
71 		type = args->v1.hasht;
72 		mask = args->v1.hashm;
73 		hidx = ffs((mask >> 8) & 0x0f) - 1;
74 	} else
75 		return ret;
76 
77 	if (!(head = nvkm_head_find(&disp->base, hidx)))
78 		return -ENXIO;
79 
80 	if (mask) {
81 		list_for_each_entry(temp, &disp->base.outp, head) {
82 			if ((temp->info.hasht         == type) &&
83 			    (temp->info.hashm & mask) == mask) {
84 				outp = temp;
85 				break;
86 			}
87 		}
88 		if (outp == NULL)
89 			return -ENXIO;
90 	}
91 
92 	switch (mthd) {
93 	case NV50_DISP_SCANOUTPOS: {
94 		return nvkm_head_mthd_scanoutpos(object, head, data, size);
95 	}
96 	default:
97 		break;
98 	}
99 
100 	switch (mthd * !!outp) {
101 	case NV50_DISP_MTHD_V1_ACQUIRE: {
102 		union {
103 			struct nv50_disp_acquire_v0 v0;
104 		} *args = data;
105 		int ret = -ENOSYS;
106 		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
107 			ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER);
108 			if (ret == 0) {
109 				args->v0.or = outp->ior->id;
110 				args->v0.link = outp->ior->asy.link;
111 			}
112 		}
113 		return ret;
114 	}
115 		break;
116 	case NV50_DISP_MTHD_V1_RELEASE:
117 		nvkm_outp_release(outp, NVKM_OUTP_USER);
118 		return 0;
119 	case NV50_DISP_MTHD_V1_DAC_LOAD: {
120 		union {
121 			struct nv50_disp_dac_load_v0 v0;
122 		} *args = data;
123 		int ret = -ENOSYS;
124 		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
125 			if (args->v0.data & 0xfff00000)
126 				return -EINVAL;
127 			ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV);
128 			if (ret)
129 				return ret;
130 			ret = outp->ior->func->sense(outp->ior, args->v0.data);
131 			nvkm_outp_release(outp, NVKM_OUTP_PRIV);
132 			if (ret < 0)
133 				return ret;
134 			args->v0.load = ret;
135 			return 0;
136 		} else
137 			return ret;
138 	}
139 		break;
140 	case NV50_DISP_MTHD_V1_SOR_HDA_ELD: {
141 		union {
142 			struct nv50_disp_sor_hda_eld_v0 v0;
143 		} *args = data;
144 		struct nvkm_ior *ior = outp->ior;
145 		int ret = -ENOSYS;
146 
147 		nvif_ioctl(object, "disp sor hda eld size %d\n", size);
148 		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
149 			nvif_ioctl(object, "disp sor hda eld vers %d\n",
150 				   args->v0.version);
151 			if (size > 0x60)
152 				return -E2BIG;
153 		} else
154 			return ret;
155 
156 		if (!ior->func->hda.hpd)
157 			return -ENODEV;
158 
159 		if (size && args->v0.data[0]) {
160 			if (outp->info.type == DCB_OUTPUT_DP)
161 				ior->func->dp.audio(ior, hidx, true);
162 			ior->func->hda.hpd(ior, hidx, true);
163 			ior->func->hda.eld(ior, data, size);
164 		} else {
165 			if (outp->info.type == DCB_OUTPUT_DP)
166 				ior->func->dp.audio(ior, hidx, false);
167 			ior->func->hda.hpd(ior, hidx, false);
168 		}
169 
170 		return 0;
171 	}
172 		break;
173 	case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: {
174 		union {
175 			struct nv50_disp_sor_hdmi_pwr_v0 v0;
176 		} *args = data;
177 		u8 *vendor, vendor_size;
178 		u8 *avi, avi_size;
179 		int ret = -ENOSYS;
180 
181 		nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
182 		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
183 			nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
184 					   "max_ac_packet %d rekey %d scdc %d\n",
185 				   args->v0.version, args->v0.state,
186 				   args->v0.max_ac_packet, args->v0.rekey,
187 				   args->v0.scdc);
188 			if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
189 				return -EINVAL;
190 			if ((args->v0.avi_infoframe_length
191 			     + args->v0.vendor_infoframe_length) > size)
192 				return -EINVAL;
193 			else
194 			if ((args->v0.avi_infoframe_length
195 			     + args->v0.vendor_infoframe_length) < size)
196 				return -E2BIG;
197 			avi = data;
198 			avi_size = args->v0.avi_infoframe_length;
199 			vendor = avi + avi_size;
200 			vendor_size = args->v0.vendor_infoframe_length;
201 		} else
202 			return ret;
203 
204 		if (!outp->ior->func->hdmi.ctrl)
205 			return -ENODEV;
206 
207 		outp->ior->func->hdmi.ctrl(outp->ior, hidx, args->v0.state,
208 					   args->v0.max_ac_packet,
209 					   args->v0.rekey, avi, avi_size,
210 					   vendor, vendor_size);
211 
212 		if (outp->ior->func->hdmi.scdc)
213 			outp->ior->func->hdmi.scdc(
214 					outp->ior, hidx, args->v0.scdc);
215 
216 		return 0;
217 	}
218 		break;
219 	case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
220 		union {
221 			struct nv50_disp_sor_lvds_script_v0 v0;
222 		} *args = data;
223 		int ret = -ENOSYS;
224 		nvif_ioctl(object, "disp sor lvds script size %d\n", size);
225 		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
226 			nvif_ioctl(object, "disp sor lvds script "
227 					   "vers %d name %04x\n",
228 				   args->v0.version, args->v0.script);
229 			disp->sor.lvdsconf = args->v0.script;
230 			return 0;
231 		} else
232 			return ret;
233 	}
234 		break;
235 	case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: {
236 		struct nvkm_dp *dp = nvkm_dp(outp);
237 		union {
238 			struct nv50_disp_sor_dp_mst_link_v0 v0;
239 		} *args = data;
240 		int ret = -ENOSYS;
241 		nvif_ioctl(object, "disp sor dp mst link size %d\n", size);
242 		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
243 			nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n",
244 				   args->v0.version, args->v0.state);
245 			dp->lt.mst = !!args->v0.state;
246 			return 0;
247 		} else
248 			return ret;
249 	}
250 		break;
251 	case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: {
252 		union {
253 			struct nv50_disp_sor_dp_mst_vcpi_v0 v0;
254 		} *args = data;
255 		int ret = -ENOSYS;
256 		nvif_ioctl(object, "disp sor dp mst vcpi size %d\n", size);
257 		if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
258 			nvif_ioctl(object, "disp sor dp mst vcpi vers %d "
259 					   "slot %02x/%02x pbn %04x/%04x\n",
260 				   args->v0.version, args->v0.start_slot,
261 				   args->v0.num_slots, args->v0.pbn,
262 				   args->v0.aligned_pbn);
263 			if (!outp->ior->func->dp.vcpi)
264 				return -ENODEV;
265 			outp->ior->func->dp.vcpi(outp->ior, hidx,
266 						 args->v0.start_slot,
267 						 args->v0.num_slots,
268 						 args->v0.pbn,
269 						 args->v0.aligned_pbn);
270 			return 0;
271 		} else
272 			return ret;
273 	}
274 		break;
275 	default:
276 		break;
277 	}
278 
279 	return -EINVAL;
280 }
281 
282 static int
nv50_disp_root_child_new_(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)283 nv50_disp_root_child_new_(const struct nvkm_oclass *oclass,
284 			  void *argv, u32 argc, struct nvkm_object **pobject)
285 {
286 	struct nv50_disp *disp = nv50_disp_root(oclass->parent)->disp;
287 	const struct nv50_disp_user *user = oclass->priv;
288 	return user->ctor(oclass, argv, argc, disp, pobject);
289 }
290 
291 static int
nv50_disp_root_child_get_(struct nvkm_object * object,int index,struct nvkm_oclass * sclass)292 nv50_disp_root_child_get_(struct nvkm_object *object, int index,
293 			  struct nvkm_oclass *sclass)
294 {
295 	struct nv50_disp_root *root = nv50_disp_root(object);
296 
297 	if (root->func->user[index].ctor) {
298 		sclass->base = root->func->user[index].base;
299 		sclass->priv = root->func->user + index;
300 		sclass->ctor = nv50_disp_root_child_new_;
301 		return 0;
302 	}
303 
304 	return -EINVAL;
305 }
306 
307 static void *
nv50_disp_root_dtor_(struct nvkm_object * object)308 nv50_disp_root_dtor_(struct nvkm_object *object)
309 {
310 	struct nv50_disp_root *root = nv50_disp_root(object);
311 	return root;
312 }
313 
314 static const struct nvkm_object_func
315 nv50_disp_root_ = {
316 	.dtor = nv50_disp_root_dtor_,
317 	.mthd = nv50_disp_root_mthd_,
318 	.ntfy = nvkm_disp_ntfy,
319 	.sclass = nv50_disp_root_child_get_,
320 };
321 
322 int
nv50_disp_root_new_(const struct nv50_disp_root_func * func,struct nvkm_disp * base,const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)323 nv50_disp_root_new_(const struct nv50_disp_root_func *func,
324 		    struct nvkm_disp *base, const struct nvkm_oclass *oclass,
325 		    void *data, u32 size, struct nvkm_object **pobject)
326 {
327 	struct nv50_disp *disp = nv50_disp(base);
328 	struct nv50_disp_root *root;
329 
330 	if (!(root = kzalloc(sizeof(*root), GFP_KERNEL)))
331 		return -ENOMEM;
332 	*pobject = &root->object;
333 
334 	nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object);
335 	root->func = func;
336 	root->disp = disp;
337 	return 0;
338 }
339 
340 static const struct nv50_disp_root_func
341 nv50_disp_root = {
342 	.user = {
343 		{{0,0,NV50_DISP_CURSOR             }, nv50_disp_curs_new },
344 		{{0,0,NV50_DISP_OVERLAY            }, nv50_disp_oimm_new },
345 		{{0,0,NV50_DISP_BASE_CHANNEL_DMA   }, nv50_disp_base_new },
346 		{{0,0,NV50_DISP_CORE_CHANNEL_DMA   }, nv50_disp_core_new },
347 		{{0,0,NV50_DISP_OVERLAY_CHANNEL_DMA}, nv50_disp_ovly_new },
348 		{}
349 	},
350 };
351 
352 static int
nv50_disp_root_new(struct nvkm_disp * disp,const struct nvkm_oclass * oclass,void * data,u32 size,struct nvkm_object ** pobject)353 nv50_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
354 		   void *data, u32 size, struct nvkm_object **pobject)
355 {
356 	return nv50_disp_root_new_(&nv50_disp_root, disp, oclass,
357 				   data, size, pobject);
358 }
359 
360 const struct nvkm_disp_oclass
361 nv50_disp_root_oclass = {
362 	.base.oclass = NV50_DISP,
363 	.base.minver = -1,
364 	.base.maxver = -1,
365 	.ctor = nv50_disp_root_new,
366 };
367