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