xref: /linux/drivers/gpu/drm/nouveau/nvkm/engine/disp/uoutp.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
11b255f1cSBen Skeggs /*
21b255f1cSBen Skeggs  * Copyright 2021 Red Hat Inc.
31b255f1cSBen Skeggs  *
41b255f1cSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
51b255f1cSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
61b255f1cSBen Skeggs  * to deal in the Software without restriction, including without limitation
71b255f1cSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81b255f1cSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
91b255f1cSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
101b255f1cSBen Skeggs  *
111b255f1cSBen Skeggs  * The above copyright notice and this permission notice shall be included in
121b255f1cSBen Skeggs  * all copies or substantial portions of the Software.
131b255f1cSBen Skeggs  *
141b255f1cSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
151b255f1cSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161b255f1cSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
171b255f1cSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
181b255f1cSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
191b255f1cSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
201b255f1cSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
211b255f1cSBen Skeggs  */
221b255f1cSBen Skeggs #define nvkm_uoutp(p) container_of((p), struct nvkm_outp, object)
231b255f1cSBen Skeggs #include "outp.h"
24a62b7493SBen Skeggs #include "dp.h"
25f530bc60SBen Skeggs #include "head.h"
26dfc4005fSBen Skeggs #include "ior.h"
271b255f1cSBen Skeggs 
28bd7a61bcSBen Skeggs #include <subdev/i2c.h>
29bd7a61bcSBen Skeggs 
301b255f1cSBen Skeggs #include <nvif/if0012.h>
311b255f1cSBen Skeggs 
321b255f1cSBen Skeggs static int
nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp * outp,void * argv,u32 argc)338c7d980dSBen Skeggs nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc)
348c7d980dSBen Skeggs {
358c7d980dSBen Skeggs 	struct nvkm_ior *ior = outp->ior;
368c7d980dSBen Skeggs 	union nvif_outp_dp_mst_vcpi_args *args = argv;
378c7d980dSBen Skeggs 
388c7d980dSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
398c7d980dSBen Skeggs 		return -ENOSYS;
408c7d980dSBen Skeggs 	if (!ior->func->dp || !ior->func->dp->vcpi || !nvkm_head_find(outp->disp, args->v0.head))
418c7d980dSBen Skeggs 		return -EINVAL;
428c7d980dSBen Skeggs 
438c7d980dSBen Skeggs 	ior->func->dp->vcpi(ior, args->v0.head, args->v0.start_slot, args->v0.num_slots,
448c7d980dSBen Skeggs 				 args->v0.pbn, args->v0.aligned_pbn);
458c7d980dSBen Skeggs 	return 0;
468c7d980dSBen Skeggs }
478c7d980dSBen Skeggs 
488c7d980dSBen Skeggs static int
nvkm_uoutp_mthd_dp_mst_id_put(struct nvkm_outp * outp,void * argv,u32 argc)491958d69fSBen Skeggs nvkm_uoutp_mthd_dp_mst_id_put(struct nvkm_outp *outp, void *argv, u32 argc)
501958d69fSBen Skeggs {
511958d69fSBen Skeggs 	union nvif_outp_dp_mst_id_put_args *args = argv;
521958d69fSBen Skeggs 
531958d69fSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
541958d69fSBen Skeggs 	        return -ENOSYS;
551958d69fSBen Skeggs 	if (!outp->func->dp.mst_id_put)
561958d69fSBen Skeggs 	        return -EINVAL;
571958d69fSBen Skeggs 
581958d69fSBen Skeggs 	return outp->func->dp.mst_id_put(outp, args->v0.id);
591958d69fSBen Skeggs }
601958d69fSBen Skeggs 
611958d69fSBen Skeggs static int
nvkm_uoutp_mthd_dp_mst_id_get(struct nvkm_outp * outp,void * argv,u32 argc)621958d69fSBen Skeggs nvkm_uoutp_mthd_dp_mst_id_get(struct nvkm_outp *outp, void *argv, u32 argc)
631958d69fSBen Skeggs {
641958d69fSBen Skeggs 	union nvif_outp_dp_mst_id_get_args *args = argv;
651958d69fSBen Skeggs 
661958d69fSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
671958d69fSBen Skeggs 	        return -ENOSYS;
681958d69fSBen Skeggs 	if (!outp->func->dp.mst_id_get)
691958d69fSBen Skeggs 	        return -EINVAL;
701958d69fSBen Skeggs 
711958d69fSBen Skeggs 	return outp->func->dp.mst_id_get(outp, &args->v0.id);
721958d69fSBen Skeggs }
731958d69fSBen Skeggs 
741958d69fSBen Skeggs static int
nvkm_uoutp_mthd_dp_sst(struct nvkm_outp * outp,void * argv,u32 argc)75e206cae1SBen Skeggs nvkm_uoutp_mthd_dp_sst(struct nvkm_outp *outp, void *argv, u32 argc)
76e206cae1SBen Skeggs {
77e206cae1SBen Skeggs 	union nvif_outp_dp_sst_args *args = argv;
78e206cae1SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
79e206cae1SBen Skeggs 	struct nvkm_ior *ior = outp->ior;
80e206cae1SBen Skeggs 
81e206cae1SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
82e206cae1SBen Skeggs 		return -ENOSYS;
83e206cae1SBen Skeggs 
84e206cae1SBen Skeggs 	if (!ior->func->dp || !nvkm_head_find(disp, args->v0.head))
85e206cae1SBen Skeggs 		return -EINVAL;
86e206cae1SBen Skeggs 	if (!ior->func->dp->sst)
87e206cae1SBen Skeggs 		return 0;
88e206cae1SBen Skeggs 
89e206cae1SBen Skeggs 	return ior->func->dp->sst(ior, args->v0.head,
90e206cae1SBen Skeggs 				  outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP,
91e206cae1SBen Skeggs 				  args->v0.watermark, args->v0.hblanksym, args->v0.vblanksym);
92e206cae1SBen Skeggs }
93e206cae1SBen Skeggs 
94e206cae1SBen Skeggs static int
nvkm_uoutp_mthd_dp_drive(struct nvkm_outp * outp,void * argv,u32 argc)953147ce0dSBen Skeggs nvkm_uoutp_mthd_dp_drive(struct nvkm_outp *outp, void *argv, u32 argc)
963147ce0dSBen Skeggs {
973147ce0dSBen Skeggs 	union nvif_outp_dp_drive_args *args = argv;
983147ce0dSBen Skeggs 
993147ce0dSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
1003147ce0dSBen Skeggs 		return -ENOSYS;
1013147ce0dSBen Skeggs 	if (!outp->func->dp.drive)
1023147ce0dSBen Skeggs 		return -EINVAL;
1033147ce0dSBen Skeggs 
1043147ce0dSBen Skeggs 	return outp->func->dp.drive(outp, args->v0.lanes, args->v0.pe, args->v0.vs);
1053147ce0dSBen Skeggs }
1063147ce0dSBen Skeggs 
1073147ce0dSBen Skeggs static int
nvkm_uoutp_mthd_dp_train(struct nvkm_outp * outp,void * argv,u32 argc)10863371650SBen Skeggs nvkm_uoutp_mthd_dp_train(struct nvkm_outp *outp, void *argv, u32 argc)
1098bb30c88SBen Skeggs {
11063371650SBen Skeggs 	union nvif_outp_dp_train_args *args = argv;
1118bb30c88SBen Skeggs 
11263371650SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
1138bb30c88SBen Skeggs 		return -ENOSYS;
11463371650SBen Skeggs 	if (!outp->func->dp.train)
11563371650SBen Skeggs 		return -EINVAL;
1168bb30c88SBen Skeggs 
11763371650SBen Skeggs 	if (!args->v0.retrain) {
11863371650SBen Skeggs 		memcpy(outp->dp.dpcd, args->v0.dpcd, sizeof(outp->dp.dpcd));
11963371650SBen Skeggs 		outp->dp.lttprs = args->v0.lttprs;
1203147ce0dSBen Skeggs 		outp->dp.lt.nr = args->v0.link_nr;
1213147ce0dSBen Skeggs 		outp->dp.lt.bw = args->v0.link_bw / 27000;
12263371650SBen Skeggs 		outp->dp.lt.mst = args->v0.mst;
12363371650SBen Skeggs 		outp->dp.lt.post_adj = args->v0.post_lt_adj;
1248bb30c88SBen Skeggs 	}
1258bb30c88SBen Skeggs 
12663371650SBen Skeggs 	return outp->func->dp.train(outp, args->v0.retrain);
12768ee1722SBen Skeggs }
12868ee1722SBen Skeggs 
12968ee1722SBen Skeggs static int
nvkm_uoutp_mthd_dp_rates(struct nvkm_outp * outp,void * argv,u32 argc)130bfb03a07SBen Skeggs nvkm_uoutp_mthd_dp_rates(struct nvkm_outp *outp, void *argv, u32 argc)
131bfb03a07SBen Skeggs {
132bfb03a07SBen Skeggs 	union nvif_outp_dp_rates_args *args = argv;
133bfb03a07SBen Skeggs 
134bfb03a07SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
135bfb03a07SBen Skeggs 		return -ENOSYS;
136bfb03a07SBen Skeggs 	if (args->v0.rates > ARRAY_SIZE(outp->dp.rate))
137bfb03a07SBen Skeggs 		return -EINVAL;
138bfb03a07SBen Skeggs 
139bfb03a07SBen Skeggs 	for (int i = 0; i < args->v0.rates; i++) {
140bfb03a07SBen Skeggs 		outp->dp.rate[i].dpcd = args->v0.rate[i].dpcd;
141bfb03a07SBen Skeggs 		outp->dp.rate[i].rate = args->v0.rate[i].rate;
142bfb03a07SBen Skeggs 	}
143bfb03a07SBen Skeggs 
144bfb03a07SBen Skeggs 	outp->dp.rates = args->v0.rates;
145bfb03a07SBen Skeggs 
146bfb03a07SBen Skeggs 	if (outp->func->dp.rates)
147bfb03a07SBen Skeggs 		outp->func->dp.rates(outp);
148bfb03a07SBen Skeggs 
149bfb03a07SBen Skeggs 	return 0;
150bfb03a07SBen Skeggs }
151bfb03a07SBen Skeggs 
152bfb03a07SBen Skeggs static int
nvkm_uoutp_mthd_dp_aux_xfer(struct nvkm_outp * outp,void * argv,u32 argc)153bd7a61bcSBen Skeggs nvkm_uoutp_mthd_dp_aux_xfer(struct nvkm_outp *outp, void *argv, u32 argc)
154bd7a61bcSBen Skeggs {
155bd7a61bcSBen Skeggs 	union nvif_outp_dp_aux_xfer_args *args = argv;
156bd7a61bcSBen Skeggs 
157bd7a61bcSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
158bd7a61bcSBen Skeggs 		return -ENOSYS;
159bd7a61bcSBen Skeggs 	if (!outp->func->dp.aux_xfer)
160bd7a61bcSBen Skeggs 		return -EINVAL;
161bd7a61bcSBen Skeggs 
162bd7a61bcSBen Skeggs 	return outp->func->dp.aux_xfer(outp, args->v0.type, args->v0.addr,
163bd7a61bcSBen Skeggs 					     args->v0.data, &args->v0.size);
164bd7a61bcSBen Skeggs }
165bd7a61bcSBen Skeggs 
166bd7a61bcSBen Skeggs static int
nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp * outp,void * argv,u32 argc)167a62b7493SBen Skeggs nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc)
168a62b7493SBen Skeggs {
169a62b7493SBen Skeggs 	union nvif_outp_dp_aux_pwr_args *args = argv;
170a62b7493SBen Skeggs 
171a62b7493SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
172a62b7493SBen Skeggs 		return -ENOSYS;
1730bd4e9f7SBen Skeggs 	if (!outp->func->dp.aux_pwr)
1740bd4e9f7SBen Skeggs 		return -EINVAL;
175a62b7493SBen Skeggs 
1760bd4e9f7SBen Skeggs 	return outp->func->dp.aux_pwr(outp, !!args->v0.state);
177a62b7493SBen Skeggs }
178a62b7493SBen Skeggs 
179a62b7493SBen Skeggs static int
nvkm_uoutp_mthd_hda_eld(struct nvkm_outp * outp,void * argv,u32 argc)180a9f5d772SBen Skeggs nvkm_uoutp_mthd_hda_eld(struct nvkm_outp *outp, void *argv, u32 argc)
181a9f5d772SBen Skeggs {
182a9f5d772SBen Skeggs 	struct nvkm_ior *ior = outp->ior;
183a9f5d772SBen Skeggs 	union nvif_outp_hda_eld_args *args = argv;
184a9f5d772SBen Skeggs 
185a9f5d772SBen Skeggs 	if (argc < sizeof(args->v0) || args->v0.version != 0)
186a9f5d772SBen Skeggs 		return -ENOSYS;
187a9f5d772SBen Skeggs 	argc -= sizeof(args->v0);
188a9f5d772SBen Skeggs 
189a9f5d772SBen Skeggs 	if (!ior->hda || !nvkm_head_find(outp->disp, args->v0.head))
190a9f5d772SBen Skeggs 		return -EINVAL;
191a9f5d772SBen Skeggs 	if (argc > 0x60)
192a9f5d772SBen Skeggs 		return -E2BIG;
193a9f5d772SBen Skeggs 
194a9f5d772SBen Skeggs 	if (argc && args->v0.data[0]) {
195a9f5d772SBen Skeggs 		if (outp->info.type == DCB_OUTPUT_DP)
196a9f5d772SBen Skeggs 			ior->func->dp->audio(ior, args->v0.head, true);
197e9c9b5b9SBen Skeggs 		else
198e9c9b5b9SBen Skeggs 		if (ior->func->hdmi->audio)
199e9c9b5b9SBen Skeggs 			ior->func->hdmi->audio(ior, args->v0.head, true);
200e9c9b5b9SBen Skeggs 
201a9f5d772SBen Skeggs 		ior->func->hda->hpd(ior, args->v0.head, true);
202a9f5d772SBen Skeggs 		ior->func->hda->eld(ior, args->v0.head, args->v0.data, argc);
203a9f5d772SBen Skeggs 	} else {
204e9c9b5b9SBen Skeggs 		ior->func->hda->hpd(ior, args->v0.head, false);
205e9c9b5b9SBen Skeggs 
206a9f5d772SBen Skeggs 		if (outp->info.type == DCB_OUTPUT_DP)
207a9f5d772SBen Skeggs 			ior->func->dp->audio(ior, args->v0.head, false);
208e9c9b5b9SBen Skeggs 		else
209e9c9b5b9SBen Skeggs 		if (ior->func->hdmi->audio)
210e9c9b5b9SBen Skeggs 			ior->func->hdmi->audio(ior, args->v0.head, false);
211a9f5d772SBen Skeggs 	}
212a9f5d772SBen Skeggs 
213a9f5d772SBen Skeggs 	return 0;
214a9f5d772SBen Skeggs }
215a9f5d772SBen Skeggs 
216a9f5d772SBen Skeggs static int
nvkm_uoutp_mthd_infoframe(struct nvkm_outp * outp,void * argv,u32 argc)217f530bc60SBen Skeggs nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc)
218f530bc60SBen Skeggs {
219f530bc60SBen Skeggs 	struct nvkm_ior *ior = outp->ior;
220f530bc60SBen Skeggs 	union nvif_outp_infoframe_args *args = argv;
221c02f20d3SBen Skeggs 	ssize_t size = argc - sizeof(*args);
222f530bc60SBen Skeggs 
223f530bc60SBen Skeggs 	if (argc < sizeof(args->v0) || args->v0.version != 0)
224f530bc60SBen Skeggs 		return -ENOSYS;
225f530bc60SBen Skeggs 	if (!nvkm_head_find(outp->disp, args->v0.head))
226f530bc60SBen Skeggs 		return -EINVAL;
227f530bc60SBen Skeggs 
228f530bc60SBen Skeggs 	switch (ior->func->hdmi ? args->v0.type : 0xff) {
229f530bc60SBen Skeggs 	case NVIF_OUTP_INFOFRAME_V0_AVI:
230c02f20d3SBen Skeggs 		ior->func->hdmi->infoframe_avi(ior, args->v0.head, &args->v0.data, size);
231f530bc60SBen Skeggs 		return 0;
232f530bc60SBen Skeggs 	case NVIF_OUTP_INFOFRAME_V0_VSI:
233c02f20d3SBen Skeggs 		ior->func->hdmi->infoframe_vsi(ior, args->v0.head, &args->v0.data, size);
234f530bc60SBen Skeggs 		return 0;
235f530bc60SBen Skeggs 	default:
236f530bc60SBen Skeggs 		break;
237f530bc60SBen Skeggs 	}
238f530bc60SBen Skeggs 
239f530bc60SBen Skeggs 	return -EINVAL;
240f530bc60SBen Skeggs }
241f530bc60SBen Skeggs 
242f530bc60SBen Skeggs static int
nvkm_uoutp_mthd_hdmi(struct nvkm_outp * outp,void * argv,u32 argc)2436c6abab2SBen Skeggs nvkm_uoutp_mthd_hdmi(struct nvkm_outp *outp, void *argv, u32 argc)
244f530bc60SBen Skeggs {
2456c6abab2SBen Skeggs 	union nvif_outp_hdmi_args *args = argv;
246cefc3c14SBen Skeggs 	struct nvkm_ior *ior = outp->ior;
247f530bc60SBen Skeggs 
2486c6abab2SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
2496c6abab2SBen Skeggs 		return -ENOSYS;
2506c6abab2SBen Skeggs 
2516c6abab2SBen Skeggs 	if (!(outp->asy.head = nvkm_head_find(outp->disp, args->v0.head)))
252f530bc60SBen Skeggs 		return -EINVAL;
253f530bc60SBen Skeggs 
254f530bc60SBen Skeggs 	if (!ior->func->hdmi ||
2556c6abab2SBen Skeggs 	    args->v0.max_ac_packet > 0x1f ||
2566c6abab2SBen Skeggs 	    args->v0.rekey > 0x7f ||
2576c6abab2SBen Skeggs 	    (args->v0.scdc && !ior->func->hdmi->scdc))
258f530bc60SBen Skeggs 		return -EINVAL;
259f530bc60SBen Skeggs 
2608ed09421SBen Skeggs 	if (!args->v0.enable) {
2618ed09421SBen Skeggs 		ior->func->hdmi->infoframe_avi(ior, args->v0.head, NULL, 0);
2628ed09421SBen Skeggs 		ior->func->hdmi->infoframe_vsi(ior, args->v0.head, NULL, 0);
2638ed09421SBen Skeggs 		ior->func->hdmi->ctrl(ior, args->v0.head, false, 0, 0);
2648ed09421SBen Skeggs 		return 0;
2658ed09421SBen Skeggs 	}
2668ed09421SBen Skeggs 
2676c6abab2SBen Skeggs 	ior->func->hdmi->ctrl(ior, args->v0.head, args->v0.enable,
2686c6abab2SBen Skeggs 			      args->v0.max_ac_packet, args->v0.rekey);
269f530bc60SBen Skeggs 	if (ior->func->hdmi->scdc)
2706c6abab2SBen Skeggs 		ior->func->hdmi->scdc(ior, args->v0.khz, args->v0.scdc, args->v0.scdc_scrambling,
2716c6abab2SBen Skeggs 				      args->v0.scdc_low_rates);
272f530bc60SBen Skeggs 
273f530bc60SBen Skeggs 	return 0;
274f530bc60SBen Skeggs }
275f530bc60SBen Skeggs 
276f530bc60SBen Skeggs static int
nvkm_uoutp_mthd_lvds(struct nvkm_outp * outp,void * argv,u32 argc)2775b9c0307SBen Skeggs nvkm_uoutp_mthd_lvds(struct nvkm_outp *outp, void *argv, u32 argc)
2789793083fSBen Skeggs {
2795b9c0307SBen Skeggs 	union nvif_outp_lvds_args *args = argv;
2805b9c0307SBen Skeggs 
2815b9c0307SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
2825b9c0307SBen Skeggs 		return -ENOSYS;
2839793083fSBen Skeggs 	if (outp->info.type != DCB_OUTPUT_LVDS)
2849793083fSBen Skeggs 		return -EINVAL;
2859793083fSBen Skeggs 
2865b9c0307SBen Skeggs 	outp->lvds.dual = !!args->v0.dual;
2875b9c0307SBen Skeggs 	outp->lvds.bpc8 = !!args->v0.bpc8;
288cefc3c14SBen Skeggs 	return 0;
2899793083fSBen Skeggs }
2909793083fSBen Skeggs 
2919793083fSBen Skeggs static int
nvkm_uoutp_mthd_bl_set(struct nvkm_outp * outp,void * argv,u32 argc)2922274ce7eSBen Skeggs nvkm_uoutp_mthd_bl_set(struct nvkm_outp *outp, void *argv, u32 argc)
2932274ce7eSBen Skeggs {
2942274ce7eSBen Skeggs 	union nvif_outp_bl_get_args *args = argv;
2952274ce7eSBen Skeggs 	int ret;
2962274ce7eSBen Skeggs 
2972274ce7eSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
2982274ce7eSBen Skeggs 		return -ENOSYS;
2992274ce7eSBen Skeggs 
3002274ce7eSBen Skeggs 	if (outp->func->bl.set)
3012274ce7eSBen Skeggs 		ret = outp->func->bl.set(outp, args->v0.level);
3022274ce7eSBen Skeggs 	else
3032274ce7eSBen Skeggs 		ret = -EINVAL;
3042274ce7eSBen Skeggs 
3052274ce7eSBen Skeggs 	return ret;
3062274ce7eSBen Skeggs }
3072274ce7eSBen Skeggs 
3082274ce7eSBen Skeggs static int
nvkm_uoutp_mthd_bl_get(struct nvkm_outp * outp,void * argv,u32 argc)3092274ce7eSBen Skeggs nvkm_uoutp_mthd_bl_get(struct nvkm_outp *outp, void *argv, u32 argc)
3102274ce7eSBen Skeggs {
3112274ce7eSBen Skeggs 	union nvif_outp_bl_get_args *args = argv;
3122274ce7eSBen Skeggs 	int ret;
3132274ce7eSBen Skeggs 
3142274ce7eSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
3152274ce7eSBen Skeggs 		return -ENOSYS;
3162274ce7eSBen Skeggs 
3172274ce7eSBen Skeggs 	if (outp->func->bl.get) {
3182274ce7eSBen Skeggs 		ret = outp->func->bl.get(outp);
3192274ce7eSBen Skeggs 		if (ret >= 0) {
3202274ce7eSBen Skeggs 			args->v0.level = ret;
3212274ce7eSBen Skeggs 			ret = 0;
3222274ce7eSBen Skeggs 		}
3232274ce7eSBen Skeggs 	} else {
3242274ce7eSBen Skeggs 		ret = -EINVAL;
3252274ce7eSBen Skeggs 	}
3262274ce7eSBen Skeggs 
3272274ce7eSBen Skeggs 	return ret;
3282274ce7eSBen Skeggs }
3292274ce7eSBen Skeggs 
3302274ce7eSBen Skeggs static int
nvkm_uoutp_mthd_release(struct nvkm_outp * outp,void * argv,u32 argc)33168ee1722SBen Skeggs nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc)
33268ee1722SBen Skeggs {
33368ee1722SBen Skeggs 	union nvif_outp_release_args *args = argv;
33468ee1722SBen Skeggs 
33568ee1722SBen Skeggs 	if (argc != sizeof(args->vn))
33668ee1722SBen Skeggs 		return -ENOSYS;
337b24bf8b8SBen Skeggs 	if (!outp->ior)
338b24bf8b8SBen Skeggs 		return -EINVAL;
33968ee1722SBen Skeggs 
3403147ce0dSBen Skeggs 	outp->func->release(outp);
34168ee1722SBen Skeggs 	return 0;
34268ee1722SBen Skeggs }
34368ee1722SBen Skeggs 
34468ee1722SBen Skeggs static int
nvkm_uoutp_mthd_acquire(struct nvkm_outp * outp,void * argv,u32 argc)345ea6143a8SBen Skeggs nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
346ea6143a8SBen Skeggs {
347ea6143a8SBen Skeggs 	union nvif_outp_acquire_args *args = argv;
348ea6143a8SBen Skeggs 	int ret;
349ea6143a8SBen Skeggs 
350ea6143a8SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
351ea6143a8SBen Skeggs 		return -ENOSYS;
352cefc3c14SBen Skeggs 	if (outp->ior && args->v0.type <= NVIF_OUTP_ACQUIRE_V0_PIOR)
35381344372SBen Skeggs 		return -EBUSY;
354ea6143a8SBen Skeggs 
355724e0f3bSBen Skeggs 	switch (args->v0.type) {
356724e0f3bSBen Skeggs 	case NVIF_OUTP_ACQUIRE_V0_DAC:
357cefc3c14SBen Skeggs 	case NVIF_OUTP_ACQUIRE_V0_PIOR:
3583147ce0dSBen Skeggs 		ret = outp->func->acquire(outp, false);
359ea6143a8SBen Skeggs 		break;
360cefc3c14SBen Skeggs 	case NVIF_OUTP_ACQUIRE_V0_SOR:
3613147ce0dSBen Skeggs 		ret = outp->func->acquire(outp, args->v0.sor.hda);
362cefc3c14SBen Skeggs 		break;
363ea6143a8SBen Skeggs 	default:
364ea6143a8SBen Skeggs 		ret = -EINVAL;
365ea6143a8SBen Skeggs 		break;
366ea6143a8SBen Skeggs 	}
367ea6143a8SBen Skeggs 
368ea6143a8SBen Skeggs 	if (ret)
369ea6143a8SBen Skeggs 		return ret;
370ea6143a8SBen Skeggs 
371ea6143a8SBen Skeggs 	args->v0.or = outp->ior->id;
372ea6143a8SBen Skeggs 	args->v0.link = outp->ior->asy.link;
373ea6143a8SBen Skeggs 	return 0;
374ea6143a8SBen Skeggs }
375ea6143a8SBen Skeggs 
376ea6143a8SBen Skeggs static int
nvkm_uoutp_mthd_inherit(struct nvkm_outp * outp,void * argv,u32 argc)3771b477f42SLyude Paul nvkm_uoutp_mthd_inherit(struct nvkm_outp *outp, void *argv, u32 argc)
3781b477f42SLyude Paul {
3791b477f42SLyude Paul 	union nvif_outp_inherit_args *args = argv;
3801b477f42SLyude Paul 	struct nvkm_ior *ior;
3811b477f42SLyude Paul 	int ret = 0;
3821b477f42SLyude Paul 
3831b477f42SLyude Paul 	if (argc != sizeof(args->v0) || args->v0.version != 0)
3841b477f42SLyude Paul 		return -ENOSYS;
3851b477f42SLyude Paul 
3861b477f42SLyude Paul 	/* Ensure an ior is hooked up to this outp already */
3871b477f42SLyude Paul 	ior = outp->func->inherit(outp);
388*7ba84cbfSLyude Paul 	if (!ior || !ior->arm.head)
3891b477f42SLyude Paul 		return -ENODEV;
3901b477f42SLyude Paul 
3911b477f42SLyude Paul 	/* With iors, there will be a separate output path for each type of connector - and all of
3921b477f42SLyude Paul 	 * them will appear to be hooked up. Figure out which one is actually the one we're using
3931b477f42SLyude Paul 	 * based on the protocol we were given over nvif
3941b477f42SLyude Paul 	 */
3951b477f42SLyude Paul 	switch (args->v0.proto) {
3961b477f42SLyude Paul 	case NVIF_OUTP_INHERIT_V0_TMDS:
3971b477f42SLyude Paul 		if (ior->arm.proto != TMDS)
3981b477f42SLyude Paul 			return -ENODEV;
3991b477f42SLyude Paul 		break;
4001b477f42SLyude Paul 	case NVIF_OUTP_INHERIT_V0_DP:
4011b477f42SLyude Paul 		if (ior->arm.proto != DP)
4021b477f42SLyude Paul 			return -ENODEV;
4031b477f42SLyude Paul 		break;
4041b477f42SLyude Paul 	case NVIF_OUTP_INHERIT_V0_LVDS:
4051b477f42SLyude Paul 		if (ior->arm.proto != LVDS)
4061b477f42SLyude Paul 			return -ENODEV;
4071b477f42SLyude Paul 		break;
4081b477f42SLyude Paul 	case NVIF_OUTP_INHERIT_V0_TV:
4091b477f42SLyude Paul 		if (ior->arm.proto != TV)
4101b477f42SLyude Paul 			return -ENODEV;
4111b477f42SLyude Paul 		break;
4121b477f42SLyude Paul 	case NVIF_OUTP_INHERIT_V0_RGB_CRT:
4131b477f42SLyude Paul 		if (ior->arm.proto != CRT)
4141b477f42SLyude Paul 			return -ENODEV;
4151b477f42SLyude Paul 		break;
4161b477f42SLyude Paul 	default:
4171b477f42SLyude Paul 		ret = -EINVAL;
4181b477f42SLyude Paul 		break;
4191b477f42SLyude Paul 	}
4201b477f42SLyude Paul 
4211b477f42SLyude Paul 	/* Make sure that userspace hasn't already acquired this */
4221b477f42SLyude Paul 	if (outp->acquired) {
4231b477f42SLyude Paul 		OUTP_ERR(outp, "cannot inherit an already acquired (%02x) outp", outp->acquired);
4241b477f42SLyude Paul 		return -EBUSY;
4251b477f42SLyude Paul 	}
4261b477f42SLyude Paul 
4271b477f42SLyude Paul 	/* Mark the outp acquired by userspace now that we've confirmed it's already active */
4281b477f42SLyude Paul 	OUTP_TRACE(outp, "inherit %02x |= %02x %p", outp->acquired, NVKM_OUTP_USER, ior);
4291b477f42SLyude Paul 	nvkm_outp_acquire_ior(outp, NVKM_OUTP_USER, ior);
4301b477f42SLyude Paul 
4311b477f42SLyude Paul 	args->v0.or = ior->id;
4321b477f42SLyude Paul 	args->v0.link = ior->arm.link;
4331b477f42SLyude Paul 	args->v0.head = ffs(ior->arm.head) - 1;
4341b477f42SLyude Paul 	args->v0.proto = ior->arm.proto_evo;
4351b477f42SLyude Paul 
4361b477f42SLyude Paul 	return ret;
4371b477f42SLyude Paul }
4381b477f42SLyude Paul 
4391b477f42SLyude Paul static int
nvkm_uoutp_mthd_load_detect(struct nvkm_outp * outp,void * argv,u32 argc)440dfc4005fSBen Skeggs nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc)
441dfc4005fSBen Skeggs {
442dfc4005fSBen Skeggs 	union nvif_outp_load_detect_args *args = argv;
443dfc4005fSBen Skeggs 	int ret;
444dfc4005fSBen Skeggs 
445dfc4005fSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
446dfc4005fSBen Skeggs 		return -ENOSYS;
447dfc4005fSBen Skeggs 
4488a7783c7SBen Skeggs 	ret = nvkm_outp_acquire_or(outp, NVKM_OUTP_PRIV, false);
449dfc4005fSBen Skeggs 	if (ret == 0) {
450dfc4005fSBen Skeggs 		if (outp->ior->func->sense) {
451dfc4005fSBen Skeggs 			ret = outp->ior->func->sense(outp->ior, args->v0.data);
452dfc4005fSBen Skeggs 			args->v0.load = ret < 0 ? 0 : ret;
453dfc4005fSBen Skeggs 		} else {
454dfc4005fSBen Skeggs 			ret = -EINVAL;
455dfc4005fSBen Skeggs 		}
4568a7783c7SBen Skeggs 		nvkm_outp_release_or(outp, NVKM_OUTP_PRIV);
457dfc4005fSBen Skeggs 	}
458dfc4005fSBen Skeggs 
459dfc4005fSBen Skeggs 	return ret;
460dfc4005fSBen Skeggs }
461dfc4005fSBen Skeggs 
462dfc4005fSBen Skeggs static int
nvkm_uoutp_mthd_edid_get(struct nvkm_outp * outp,void * argv,u32 argc)4630cd7e071SBen Skeggs nvkm_uoutp_mthd_edid_get(struct nvkm_outp *outp, void *argv, u32 argc)
4640cd7e071SBen Skeggs {
4650cd7e071SBen Skeggs 	union nvif_outp_edid_get_args *args = argv;
4660cd7e071SBen Skeggs 
4670cd7e071SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
4680cd7e071SBen Skeggs 		return -ENOSYS;
4690cd7e071SBen Skeggs 	if (!outp->func->edid_get)
4700cd7e071SBen Skeggs 		return -EINVAL;
4710cd7e071SBen Skeggs 
4720cd7e071SBen Skeggs 	args->v0.size = ARRAY_SIZE(args->v0.data);
4730cd7e071SBen Skeggs 	return outp->func->edid_get(outp, args->v0.data, &args->v0.size);
4740cd7e071SBen Skeggs }
4750cd7e071SBen Skeggs 
4760cd7e071SBen Skeggs static int
nvkm_uoutp_mthd_detect(struct nvkm_outp * outp,void * argv,u32 argc)477a69eeb37SBen Skeggs nvkm_uoutp_mthd_detect(struct nvkm_outp *outp, void *argv, u32 argc)
478a69eeb37SBen Skeggs {
479a69eeb37SBen Skeggs 	union nvif_outp_detect_args *args = argv;
480a69eeb37SBen Skeggs 	int ret;
481a69eeb37SBen Skeggs 
482a69eeb37SBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
483a69eeb37SBen Skeggs 		return -ENOSYS;
484a69eeb37SBen Skeggs 	if (!outp->func->detect)
485a69eeb37SBen Skeggs 		return -EINVAL;
486a69eeb37SBen Skeggs 
487a69eeb37SBen Skeggs 	ret = outp->func->detect(outp);
488a69eeb37SBen Skeggs 	switch (ret) {
489a69eeb37SBen Skeggs 	case 0: args->v0.status = NVIF_OUTP_DETECT_V0_NOT_PRESENT; break;
490a69eeb37SBen Skeggs 	case 1: args->v0.status = NVIF_OUTP_DETECT_V0_PRESENT; break;
491a69eeb37SBen Skeggs 	default:
492a69eeb37SBen Skeggs 		args->v0.status = NVIF_OUTP_DETECT_V0_UNKNOWN;
493a69eeb37SBen Skeggs 		break;
494a69eeb37SBen Skeggs 	}
495a69eeb37SBen Skeggs 
496a69eeb37SBen Skeggs 	return 0;
497a69eeb37SBen Skeggs }
498a69eeb37SBen Skeggs 
499a69eeb37SBen Skeggs static int
nvkm_uoutp_mthd_acquired(struct nvkm_outp * outp,u32 mthd,void * argv,u32 argc)500ea6143a8SBen Skeggs nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
501ea6143a8SBen Skeggs {
502ea6143a8SBen Skeggs 	switch (mthd) {
503ea6143a8SBen Skeggs 	case NVIF_OUTP_V0_RELEASE      : return nvkm_uoutp_mthd_release      (outp, argv, argc);
5045b9c0307SBen Skeggs 	case NVIF_OUTP_V0_LVDS         : return nvkm_uoutp_mthd_lvds         (outp, argv, argc);
5056c6abab2SBen Skeggs 	case NVIF_OUTP_V0_HDMI         : return nvkm_uoutp_mthd_hdmi         (outp, argv, argc);
506f530bc60SBen Skeggs 	case NVIF_OUTP_V0_INFOFRAME    : return nvkm_uoutp_mthd_infoframe    (outp, argv, argc);
507a9f5d772SBen Skeggs 	case NVIF_OUTP_V0_HDA_ELD      : return nvkm_uoutp_mthd_hda_eld      (outp, argv, argc);
50863371650SBen Skeggs 	case NVIF_OUTP_V0_DP_TRAIN     : return nvkm_uoutp_mthd_dp_train     (outp, argv, argc);
5093147ce0dSBen Skeggs 	case NVIF_OUTP_V0_DP_DRIVE     : return nvkm_uoutp_mthd_dp_drive     (outp, argv, argc);
510e206cae1SBen Skeggs 	case NVIF_OUTP_V0_DP_SST       : return nvkm_uoutp_mthd_dp_sst       (outp, argv, argc);
5111958d69fSBen Skeggs 	case NVIF_OUTP_V0_DP_MST_ID_GET: return nvkm_uoutp_mthd_dp_mst_id_get(outp, argv, argc);
5121958d69fSBen Skeggs 	case NVIF_OUTP_V0_DP_MST_ID_PUT: return nvkm_uoutp_mthd_dp_mst_id_put(outp, argv, argc);
5138c7d980dSBen Skeggs 	case NVIF_OUTP_V0_DP_MST_VCPI  : return nvkm_uoutp_mthd_dp_mst_vcpi  (outp, argv, argc);
514ea6143a8SBen Skeggs 	default:
515ea6143a8SBen Skeggs 		break;
516ea6143a8SBen Skeggs 	}
517ea6143a8SBen Skeggs 
518ea6143a8SBen Skeggs 	return -EINVAL;
519ea6143a8SBen Skeggs }
520ea6143a8SBen Skeggs 
521ea6143a8SBen Skeggs static int
nvkm_uoutp_mthd_noacquire(struct nvkm_outp * outp,u32 mthd,void * argv,u32 argc,bool * invalid)522bd7a61bcSBen Skeggs nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc, bool *invalid)
5231b255f1cSBen Skeggs {
5241b255f1cSBen Skeggs 	switch (mthd) {
525a69eeb37SBen Skeggs 	case NVIF_OUTP_V0_DETECT     : return nvkm_uoutp_mthd_detect     (outp, argv, argc);
5260cd7e071SBen Skeggs 	case NVIF_OUTP_V0_EDID_GET   : return nvkm_uoutp_mthd_edid_get   (outp, argv, argc);
5271b477f42SLyude Paul 	case NVIF_OUTP_V0_INHERIT    : return nvkm_uoutp_mthd_inherit    (outp, argv, argc);
528ea6143a8SBen Skeggs 	case NVIF_OUTP_V0_ACQUIRE    : return nvkm_uoutp_mthd_acquire    (outp, argv, argc);
52921636b1aSBen Skeggs 	case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc);
5302274ce7eSBen Skeggs 	case NVIF_OUTP_V0_BL_GET     : return nvkm_uoutp_mthd_bl_get     (outp, argv, argc);
5312274ce7eSBen Skeggs 	case NVIF_OUTP_V0_BL_SET     : return nvkm_uoutp_mthd_bl_set     (outp, argv, argc);
532a62b7493SBen Skeggs 	case NVIF_OUTP_V0_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc);
533bd7a61bcSBen Skeggs 	case NVIF_OUTP_V0_DP_AUX_XFER: return nvkm_uoutp_mthd_dp_aux_xfer(outp, argv, argc);
534bfb03a07SBen Skeggs 	case NVIF_OUTP_V0_DP_RATES   : return nvkm_uoutp_mthd_dp_rates   (outp, argv, argc);
5351b255f1cSBen Skeggs 	default:
5361b255f1cSBen Skeggs 		break;
5371b255f1cSBen Skeggs 	}
5381b255f1cSBen Skeggs 
539bd7a61bcSBen Skeggs 	*invalid = true;
540bd7a61bcSBen Skeggs 	return 0;
5411b255f1cSBen Skeggs }
5421b255f1cSBen Skeggs 
5431b255f1cSBen Skeggs static int
nvkm_uoutp_mthd(struct nvkm_object * object,u32 mthd,void * argv,u32 argc)5441b255f1cSBen Skeggs nvkm_uoutp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
5451b255f1cSBen Skeggs {
5461b255f1cSBen Skeggs 	struct nvkm_outp *outp = nvkm_uoutp(object);
5471b255f1cSBen Skeggs 	struct nvkm_disp *disp = outp->disp;
548bd7a61bcSBen Skeggs 	bool invalid = false;
5491b255f1cSBen Skeggs 	int ret;
5501b255f1cSBen Skeggs 
5511b255f1cSBen Skeggs 	mutex_lock(&disp->super.mutex);
5521b255f1cSBen Skeggs 
553bd7a61bcSBen Skeggs 	ret = nvkm_uoutp_mthd_noacquire(outp, mthd, argv, argc, &invalid);
554bd7a61bcSBen Skeggs 	if (!invalid)
5551b255f1cSBen Skeggs 		goto done;
5561b255f1cSBen Skeggs 
557ea6143a8SBen Skeggs 	if (outp->ior)
558ea6143a8SBen Skeggs 		ret = nvkm_uoutp_mthd_acquired(outp, mthd, argv, argc);
559ea6143a8SBen Skeggs 	else
560ea6143a8SBen Skeggs 		ret = -EIO;
561ea6143a8SBen Skeggs 
5621b255f1cSBen Skeggs done:
5631b255f1cSBen Skeggs 	mutex_unlock(&disp->super.mutex);
5641b255f1cSBen Skeggs 	return ret;
5651b255f1cSBen Skeggs }
5661b255f1cSBen Skeggs 
5671b255f1cSBen Skeggs static void *
nvkm_uoutp_dtor(struct nvkm_object * object)5681b255f1cSBen Skeggs nvkm_uoutp_dtor(struct nvkm_object *object)
5691b255f1cSBen Skeggs {
5701b255f1cSBen Skeggs 	struct nvkm_outp *outp = nvkm_uoutp(object);
5711b255f1cSBen Skeggs 	struct nvkm_disp *disp = outp->disp;
5721b255f1cSBen Skeggs 
5731b255f1cSBen Skeggs 	spin_lock(&disp->client.lock);
5741b255f1cSBen Skeggs 	outp->object.func = NULL;
5751b255f1cSBen Skeggs 	spin_unlock(&disp->client.lock);
5761b255f1cSBen Skeggs 	return NULL;
5771b255f1cSBen Skeggs }
5781b255f1cSBen Skeggs 
5791b255f1cSBen Skeggs static const struct nvkm_object_func
5801b255f1cSBen Skeggs nvkm_uoutp = {
5811b255f1cSBen Skeggs 	.dtor = nvkm_uoutp_dtor,
5821b255f1cSBen Skeggs 	.mthd = nvkm_uoutp_mthd,
5831b255f1cSBen Skeggs };
5841b255f1cSBen Skeggs 
5851b255f1cSBen Skeggs int
nvkm_uoutp_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)5861b255f1cSBen Skeggs nvkm_uoutp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject)
5871b255f1cSBen Skeggs {
5881b255f1cSBen Skeggs 	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
5891b255f1cSBen Skeggs 	struct nvkm_outp *outt, *outp = NULL;
5901b255f1cSBen Skeggs 	union nvif_outp_args *args = argv;
5911b255f1cSBen Skeggs 	int ret;
5921b255f1cSBen Skeggs 
5931b255f1cSBen Skeggs 	if (argc != sizeof(args->v0) || args->v0.version != 0)
5941b255f1cSBen Skeggs 		return -ENOSYS;
5951b255f1cSBen Skeggs 
5961b255f1cSBen Skeggs 	list_for_each_entry(outt, &disp->outps, head) {
5971b255f1cSBen Skeggs 		if (outt->index == args->v0.id) {
5981b255f1cSBen Skeggs 			outp = outt;
5991b255f1cSBen Skeggs 			break;
6001b255f1cSBen Skeggs 		}
6011b255f1cSBen Skeggs 	}
6021b255f1cSBen Skeggs 
6031b255f1cSBen Skeggs 	if (!outp)
6041b255f1cSBen Skeggs 		return -EINVAL;
6051b255f1cSBen Skeggs 
6061b255f1cSBen Skeggs 	ret = -EBUSY;
6071b255f1cSBen Skeggs 	spin_lock(&disp->client.lock);
6081b255f1cSBen Skeggs 	if (!outp->object.func) {
6090a4410a7SBen Skeggs 		switch (outp->info.type) {
6100a4410a7SBen Skeggs 		case DCB_OUTPUT_ANALOG:
6110a4410a7SBen Skeggs 			args->v0.type = NVIF_OUTP_V0_TYPE_DAC;
6120a4410a7SBen Skeggs 			args->v0.proto = NVIF_OUTP_V0_PROTO_RGB_CRT;
6130a4410a7SBen Skeggs 			args->v0.rgb_crt.freq_max = outp->info.crtconf.maxfreq;
6140a4410a7SBen Skeggs 			break;
6150a4410a7SBen Skeggs 		case DCB_OUTPUT_TMDS:
6160a4410a7SBen Skeggs 			if (!outp->info.location) {
6170a4410a7SBen Skeggs 				args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
6180a4410a7SBen Skeggs 				args->v0.tmds.dual = (outp->info.tmdsconf.sor.link == 3);
6190a4410a7SBen Skeggs 			} else {
6200a4410a7SBen Skeggs 				args->v0.type = NVIF_OUTP_V0_TYPE_PIOR;
6210a4410a7SBen Skeggs 				args->v0.tmds.dual = 0;
6220a4410a7SBen Skeggs 			}
6230a4410a7SBen Skeggs 			args->v0.proto = NVIF_OUTP_V0_PROTO_TMDS;
6240a4410a7SBen Skeggs 			break;
6250a4410a7SBen Skeggs 		case DCB_OUTPUT_LVDS:
6260a4410a7SBen Skeggs 			args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
6270a4410a7SBen Skeggs 			args->v0.proto = NVIF_OUTP_V0_PROTO_LVDS;
6280a4410a7SBen Skeggs 			args->v0.lvds.acpi_edid = outp->info.lvdsconf.use_acpi_for_edid;
6290a4410a7SBen Skeggs 			break;
6300a4410a7SBen Skeggs 		case DCB_OUTPUT_DP:
6310a4410a7SBen Skeggs 			if (!outp->info.location) {
6320a4410a7SBen Skeggs 				args->v0.type = NVIF_OUTP_V0_TYPE_SOR;
6330a4410a7SBen Skeggs 				args->v0.dp.aux = outp->info.i2c_index;
6340a4410a7SBen Skeggs 			} else {
6350a4410a7SBen Skeggs 				args->v0.type = NVIF_OUTP_V0_TYPE_PIOR;
6360a4410a7SBen Skeggs 				args->v0.dp.aux = NVKM_I2C_AUX_EXT(outp->info.extdev);
6370a4410a7SBen Skeggs 			}
6380a4410a7SBen Skeggs 			args->v0.proto = NVIF_OUTP_V0_PROTO_DP;
6390a4410a7SBen Skeggs 			args->v0.dp.mst = outp->dp.mst;
6400a4410a7SBen Skeggs 			args->v0.dp.increased_wm = outp->dp.increased_wm;
6410a4410a7SBen Skeggs 			args->v0.dp.link_nr = outp->info.dpconf.link_nr;
6420a4410a7SBen Skeggs 			args->v0.dp.link_bw = outp->info.dpconf.link_bw * 27000;
6430a4410a7SBen Skeggs 			break;
6440a4410a7SBen Skeggs 		default:
6450a4410a7SBen Skeggs 			WARN_ON(1);
6460a4410a7SBen Skeggs 			ret = -EINVAL;
6470a4410a7SBen Skeggs 			goto done;
6480a4410a7SBen Skeggs 		}
6490a4410a7SBen Skeggs 
6500a4410a7SBen Skeggs 		if (outp->info.location)
6510a4410a7SBen Skeggs 			args->v0.ddc = NVKM_I2C_BUS_EXT(outp->info.extdev);
6520a4410a7SBen Skeggs 		else
6530a4410a7SBen Skeggs 			args->v0.ddc = outp->info.i2c_index;
6540a4410a7SBen Skeggs 		args->v0.heads = outp->info.heads;
6550a4410a7SBen Skeggs 		args->v0.conn = outp->info.connector;
6560a4410a7SBen Skeggs 
6571b255f1cSBen Skeggs 		nvkm_object_ctor(&nvkm_uoutp, oclass, &outp->object);
6581b255f1cSBen Skeggs 		*pobject = &outp->object;
6591b255f1cSBen Skeggs 		ret = 0;
6601b255f1cSBen Skeggs 	}
6610a4410a7SBen Skeggs 
6620a4410a7SBen Skeggs done:
6631b255f1cSBen Skeggs 	spin_unlock(&disp->client.lock);
6641b255f1cSBen Skeggs 	return ret;
6651b255f1cSBen Skeggs }
666