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
281b255f1cSBen Skeggs #include <nvif/if0012.h>
291b255f1cSBen Skeggs
301b255f1cSBen Skeggs static int
nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp * outp,void * argv,u32 argc)318c7d980dSBen Skeggs nvkm_uoutp_mthd_dp_mst_vcpi(struct nvkm_outp *outp, void *argv, u32 argc)
328c7d980dSBen Skeggs {
338c7d980dSBen Skeggs struct nvkm_ior *ior = outp->ior;
348c7d980dSBen Skeggs union nvif_outp_dp_mst_vcpi_args *args = argv;
358c7d980dSBen Skeggs
368c7d980dSBen Skeggs if (argc != sizeof(args->v0) || args->v0.version != 0)
378c7d980dSBen Skeggs return -ENOSYS;
388c7d980dSBen Skeggs if (!ior->func->dp || !ior->func->dp->vcpi || !nvkm_head_find(outp->disp, args->v0.head))
398c7d980dSBen Skeggs return -EINVAL;
408c7d980dSBen Skeggs
418c7d980dSBen Skeggs ior->func->dp->vcpi(ior, args->v0.head, args->v0.start_slot, args->v0.num_slots,
428c7d980dSBen Skeggs args->v0.pbn, args->v0.aligned_pbn);
438c7d980dSBen Skeggs return 0;
448c7d980dSBen Skeggs }
458c7d980dSBen Skeggs
468c7d980dSBen Skeggs static int
nvkm_uoutp_mthd_dp_retrain(struct nvkm_outp * outp,void * argv,u32 argc)478bb30c88SBen Skeggs nvkm_uoutp_mthd_dp_retrain(struct nvkm_outp *outp, void *argv, u32 argc)
488bb30c88SBen Skeggs {
498bb30c88SBen Skeggs union nvif_outp_dp_retrain_args *args = argv;
508bb30c88SBen Skeggs
518bb30c88SBen Skeggs if (argc != sizeof(args->vn))
528bb30c88SBen Skeggs return -ENOSYS;
538bb30c88SBen Skeggs
548bb30c88SBen Skeggs if (!atomic_read(&outp->dp.lt.done))
558bb30c88SBen Skeggs return 0;
568bb30c88SBen Skeggs
578bb30c88SBen Skeggs return outp->func->acquire(outp);
588bb30c88SBen Skeggs }
598bb30c88SBen Skeggs
608bb30c88SBen Skeggs static int
nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp * outp,void * argv,u32 argc)61a62b7493SBen Skeggs nvkm_uoutp_mthd_dp_aux_pwr(struct nvkm_outp *outp, void *argv, u32 argc)
62a62b7493SBen Skeggs {
63a62b7493SBen Skeggs union nvif_outp_dp_aux_pwr_args *args = argv;
64a62b7493SBen Skeggs
65a62b7493SBen Skeggs if (argc != sizeof(args->v0) || args->v0.version != 0)
66a62b7493SBen Skeggs return -ENOSYS;
67a62b7493SBen Skeggs
68a62b7493SBen Skeggs outp->dp.enabled = !!args->v0.state;
69a62b7493SBen Skeggs nvkm_dp_enable(outp, outp->dp.enabled);
70a62b7493SBen Skeggs return 0;
71a62b7493SBen Skeggs }
72a62b7493SBen Skeggs
73a62b7493SBen Skeggs static int
nvkm_uoutp_mthd_hda_eld(struct nvkm_outp * outp,void * argv,u32 argc)74a9f5d772SBen Skeggs nvkm_uoutp_mthd_hda_eld(struct nvkm_outp *outp, void *argv, u32 argc)
75a9f5d772SBen Skeggs {
76a9f5d772SBen Skeggs struct nvkm_ior *ior = outp->ior;
77a9f5d772SBen Skeggs union nvif_outp_hda_eld_args *args = argv;
78a9f5d772SBen Skeggs
79a9f5d772SBen Skeggs if (argc < sizeof(args->v0) || args->v0.version != 0)
80a9f5d772SBen Skeggs return -ENOSYS;
81a9f5d772SBen Skeggs argc -= sizeof(args->v0);
82a9f5d772SBen Skeggs
83a9f5d772SBen Skeggs if (!ior->hda || !nvkm_head_find(outp->disp, args->v0.head))
84a9f5d772SBen Skeggs return -EINVAL;
85a9f5d772SBen Skeggs if (argc > 0x60)
86a9f5d772SBen Skeggs return -E2BIG;
87a9f5d772SBen Skeggs
88a9f5d772SBen Skeggs if (argc && args->v0.data[0]) {
89a9f5d772SBen Skeggs if (outp->info.type == DCB_OUTPUT_DP)
90a9f5d772SBen Skeggs ior->func->dp->audio(ior, args->v0.head, true);
91a9f5d772SBen Skeggs ior->func->hda->hpd(ior, args->v0.head, true);
92a9f5d772SBen Skeggs ior->func->hda->eld(ior, args->v0.head, args->v0.data, argc);
93a9f5d772SBen Skeggs } else {
94a9f5d772SBen Skeggs if (outp->info.type == DCB_OUTPUT_DP)
95a9f5d772SBen Skeggs ior->func->dp->audio(ior, args->v0.head, false);
96a9f5d772SBen Skeggs ior->func->hda->hpd(ior, args->v0.head, false);
97a9f5d772SBen Skeggs }
98a9f5d772SBen Skeggs
99a9f5d772SBen Skeggs return 0;
100a9f5d772SBen Skeggs }
101a9f5d772SBen Skeggs
102a9f5d772SBen Skeggs static int
nvkm_uoutp_mthd_infoframe(struct nvkm_outp * outp,void * argv,u32 argc)103f530bc60SBen Skeggs nvkm_uoutp_mthd_infoframe(struct nvkm_outp *outp, void *argv, u32 argc)
104f530bc60SBen Skeggs {
105f530bc60SBen Skeggs struct nvkm_ior *ior = outp->ior;
106f530bc60SBen Skeggs union nvif_outp_infoframe_args *args = argv;
107c02f20d3SBen Skeggs ssize_t size = argc - sizeof(*args);
108f530bc60SBen Skeggs
109f530bc60SBen Skeggs if (argc < sizeof(args->v0) || args->v0.version != 0)
110f530bc60SBen Skeggs return -ENOSYS;
111f530bc60SBen Skeggs if (!nvkm_head_find(outp->disp, args->v0.head))
112f530bc60SBen Skeggs return -EINVAL;
113f530bc60SBen Skeggs
114f530bc60SBen Skeggs switch (ior->func->hdmi ? args->v0.type : 0xff) {
115f530bc60SBen Skeggs case NVIF_OUTP_INFOFRAME_V0_AVI:
116c02f20d3SBen Skeggs ior->func->hdmi->infoframe_avi(ior, args->v0.head, &args->v0.data, size);
117f530bc60SBen Skeggs return 0;
118f530bc60SBen Skeggs case NVIF_OUTP_INFOFRAME_V0_VSI:
119c02f20d3SBen Skeggs ior->func->hdmi->infoframe_vsi(ior, args->v0.head, &args->v0.data, size);
120f530bc60SBen Skeggs return 0;
121f530bc60SBen Skeggs default:
122f530bc60SBen Skeggs break;
123f530bc60SBen Skeggs }
124f530bc60SBen Skeggs
125f530bc60SBen Skeggs return -EINVAL;
126f530bc60SBen Skeggs }
127f530bc60SBen Skeggs
128f530bc60SBen Skeggs static int
nvkm_uoutp_mthd_release(struct nvkm_outp * outp,void * argv,u32 argc)129ea6143a8SBen Skeggs nvkm_uoutp_mthd_release(struct nvkm_outp *outp, void *argv, u32 argc)
130ea6143a8SBen Skeggs {
131f530bc60SBen Skeggs struct nvkm_head *head = outp->asy.head;
132f530bc60SBen Skeggs struct nvkm_ior *ior = outp->ior;
133ea6143a8SBen Skeggs union nvif_outp_release_args *args = argv;
134ea6143a8SBen Skeggs
135ea6143a8SBen Skeggs if (argc != sizeof(args->vn))
136ea6143a8SBen Skeggs return -ENOSYS;
137ea6143a8SBen Skeggs
138f530bc60SBen Skeggs if (ior->func->hdmi && head) {
139f530bc60SBen Skeggs ior->func->hdmi->infoframe_avi(ior, head->id, NULL, 0);
140f530bc60SBen Skeggs ior->func->hdmi->infoframe_vsi(ior, head->id, NULL, 0);
141f530bc60SBen Skeggs ior->func->hdmi->ctrl(ior, head->id, false, 0, 0);
142f530bc60SBen Skeggs }
143f530bc60SBen Skeggs
144ea6143a8SBen Skeggs nvkm_outp_release(outp, NVKM_OUTP_USER);
145ea6143a8SBen Skeggs return 0;
146ea6143a8SBen Skeggs }
147ea6143a8SBen Skeggs
148ea6143a8SBen Skeggs static int
nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp * outp,u8 dpcd[DP_RECEIVER_CAP_SIZE],u8 link_nr,u8 link_bw,bool hda,bool mst)149*25feda6fSKees Cook nvkm_uoutp_mthd_acquire_dp(struct nvkm_outp *outp, u8 dpcd[DP_RECEIVER_CAP_SIZE],
15081344372SBen Skeggs u8 link_nr, u8 link_bw, bool hda, bool mst)
15181344372SBen Skeggs {
15281344372SBen Skeggs int ret;
15381344372SBen Skeggs
15481344372SBen Skeggs ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hda);
15581344372SBen Skeggs if (ret)
15681344372SBen Skeggs return ret;
15781344372SBen Skeggs
15881344372SBen Skeggs memcpy(outp->dp.dpcd, dpcd, sizeof(outp->dp.dpcd));
15981344372SBen Skeggs outp->dp.lt.nr = link_nr;
16081344372SBen Skeggs outp->dp.lt.bw = link_bw;
16181344372SBen Skeggs outp->dp.lt.mst = mst;
16281344372SBen Skeggs return 0;
16381344372SBen Skeggs }
16481344372SBen Skeggs
16581344372SBen Skeggs static int
nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp * outp,u8 head,u8 hdmi,u8 hdmi_max_ac_packet,u8 hdmi_rekey,u8 hdmi_scdc,u8 hdmi_hda)166f530bc60SBen Skeggs nvkm_uoutp_mthd_acquire_tmds(struct nvkm_outp *outp, u8 head, u8 hdmi, u8 hdmi_max_ac_packet,
167f530bc60SBen Skeggs u8 hdmi_rekey, u8 hdmi_scdc, u8 hdmi_hda)
168f530bc60SBen Skeggs {
169f530bc60SBen Skeggs struct nvkm_ior *ior;
170f530bc60SBen Skeggs int ret;
171f530bc60SBen Skeggs
172f530bc60SBen Skeggs if (!(outp->asy.head = nvkm_head_find(outp->disp, head)))
173f530bc60SBen Skeggs return -EINVAL;
174f530bc60SBen Skeggs
175f530bc60SBen Skeggs ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, hdmi && hdmi_hda);
176f530bc60SBen Skeggs if (ret)
177f530bc60SBen Skeggs return ret;
178f530bc60SBen Skeggs
179f530bc60SBen Skeggs ior = outp->ior;
180f530bc60SBen Skeggs
181f530bc60SBen Skeggs if (hdmi) {
182f530bc60SBen Skeggs if (!ior->func->hdmi ||
183f530bc60SBen Skeggs hdmi_max_ac_packet > 0x1f || hdmi_rekey > 0x7f ||
184f530bc60SBen Skeggs (hdmi_scdc && !ior->func->hdmi->scdc)) {
185f530bc60SBen Skeggs nvkm_outp_release(outp, NVKM_OUTP_USER);
186f530bc60SBen Skeggs return -EINVAL;
187f530bc60SBen Skeggs }
188f530bc60SBen Skeggs
189f530bc60SBen Skeggs ior->func->hdmi->ctrl(ior, head, hdmi, hdmi_max_ac_packet, hdmi_rekey);
190f530bc60SBen Skeggs if (ior->func->hdmi->scdc)
191f530bc60SBen Skeggs ior->func->hdmi->scdc(ior, hdmi_scdc);
192f530bc60SBen Skeggs }
193f530bc60SBen Skeggs
194f530bc60SBen Skeggs return 0;
195f530bc60SBen Skeggs }
196f530bc60SBen Skeggs
197f530bc60SBen Skeggs static int
nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp * outp,bool dual,bool bpc8)1989793083fSBen Skeggs nvkm_uoutp_mthd_acquire_lvds(struct nvkm_outp *outp, bool dual, bool bpc8)
1999793083fSBen Skeggs {
2009793083fSBen Skeggs if (outp->info.type != DCB_OUTPUT_LVDS)
2019793083fSBen Skeggs return -EINVAL;
2029793083fSBen Skeggs
2039793083fSBen Skeggs outp->lvds.dual = dual;
2049793083fSBen Skeggs outp->lvds.bpc8 = bpc8;
2059793083fSBen Skeggs
2069793083fSBen Skeggs return nvkm_outp_acquire(outp, NVKM_OUTP_USER, false);
2079793083fSBen Skeggs }
2089793083fSBen Skeggs
2099793083fSBen Skeggs static int
nvkm_uoutp_mthd_acquire(struct nvkm_outp * outp,void * argv,u32 argc)210ea6143a8SBen Skeggs nvkm_uoutp_mthd_acquire(struct nvkm_outp *outp, void *argv, u32 argc)
211ea6143a8SBen Skeggs {
212ea6143a8SBen Skeggs union nvif_outp_acquire_args *args = argv;
213ea6143a8SBen Skeggs int ret;
214ea6143a8SBen Skeggs
215ea6143a8SBen Skeggs if (argc != sizeof(args->v0) || args->v0.version != 0)
216ea6143a8SBen Skeggs return -ENOSYS;
21781344372SBen Skeggs if (outp->ior)
21881344372SBen Skeggs return -EBUSY;
219ea6143a8SBen Skeggs
220ea6143a8SBen Skeggs switch (args->v0.proto) {
221ea6143a8SBen Skeggs case NVIF_OUTP_ACQUIRE_V0_RGB_CRT:
222ea6143a8SBen Skeggs ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER, false);
223ea6143a8SBen Skeggs break;
224ea6143a8SBen Skeggs case NVIF_OUTP_ACQUIRE_V0_TMDS:
225f530bc60SBen Skeggs ret = nvkm_uoutp_mthd_acquire_tmds(outp, args->v0.tmds.head,
226f530bc60SBen Skeggs args->v0.tmds.hdmi,
227f530bc60SBen Skeggs args->v0.tmds.hdmi_max_ac_packet,
228f530bc60SBen Skeggs args->v0.tmds.hdmi_rekey,
229f530bc60SBen Skeggs args->v0.tmds.hdmi_scdc,
230f530bc60SBen Skeggs args->v0.tmds.hdmi_hda);
231f530bc60SBen Skeggs break;
2329793083fSBen Skeggs case NVIF_OUTP_ACQUIRE_V0_LVDS:
2339793083fSBen Skeggs ret = nvkm_uoutp_mthd_acquire_lvds(outp, args->v0.lvds.dual, args->v0.lvds.bpc8);
2349793083fSBen Skeggs break;
23581344372SBen Skeggs case NVIF_OUTP_ACQUIRE_V0_DP:
23681344372SBen Skeggs ret = nvkm_uoutp_mthd_acquire_dp(outp, args->v0.dp.dpcd,
23781344372SBen Skeggs args->v0.dp.link_nr,
23881344372SBen Skeggs args->v0.dp.link_bw,
23981344372SBen Skeggs args->v0.dp.hda != 0,
24081344372SBen Skeggs args->v0.dp.mst != 0);
24181344372SBen Skeggs break;
242ea6143a8SBen Skeggs default:
243ea6143a8SBen Skeggs ret = -EINVAL;
244ea6143a8SBen Skeggs break;
245ea6143a8SBen Skeggs }
246ea6143a8SBen Skeggs
247ea6143a8SBen Skeggs if (ret)
248ea6143a8SBen Skeggs return ret;
249ea6143a8SBen Skeggs
250ea6143a8SBen Skeggs args->v0.or = outp->ior->id;
251ea6143a8SBen Skeggs args->v0.link = outp->ior->asy.link;
252ea6143a8SBen Skeggs return 0;
253ea6143a8SBen Skeggs }
254ea6143a8SBen Skeggs
255ea6143a8SBen Skeggs static int
nvkm_uoutp_mthd_load_detect(struct nvkm_outp * outp,void * argv,u32 argc)256dfc4005fSBen Skeggs nvkm_uoutp_mthd_load_detect(struct nvkm_outp *outp, void *argv, u32 argc)
257dfc4005fSBen Skeggs {
258dfc4005fSBen Skeggs union nvif_outp_load_detect_args *args = argv;
259dfc4005fSBen Skeggs int ret;
260dfc4005fSBen Skeggs
261dfc4005fSBen Skeggs if (argc != sizeof(args->v0) || args->v0.version != 0)
262dfc4005fSBen Skeggs return -ENOSYS;
263dfc4005fSBen Skeggs
264dfc4005fSBen Skeggs ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV, false);
265dfc4005fSBen Skeggs if (ret == 0) {
266dfc4005fSBen Skeggs if (outp->ior->func->sense) {
267dfc4005fSBen Skeggs ret = outp->ior->func->sense(outp->ior, args->v0.data);
268dfc4005fSBen Skeggs args->v0.load = ret < 0 ? 0 : ret;
269dfc4005fSBen Skeggs } else {
270dfc4005fSBen Skeggs ret = -EINVAL;
271dfc4005fSBen Skeggs }
272dfc4005fSBen Skeggs nvkm_outp_release(outp, NVKM_OUTP_PRIV);
273dfc4005fSBen Skeggs }
274dfc4005fSBen Skeggs
275dfc4005fSBen Skeggs return ret;
276dfc4005fSBen Skeggs }
277dfc4005fSBen Skeggs
278dfc4005fSBen Skeggs static int
nvkm_uoutp_mthd_acquired(struct nvkm_outp * outp,u32 mthd,void * argv,u32 argc)279ea6143a8SBen Skeggs nvkm_uoutp_mthd_acquired(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
280ea6143a8SBen Skeggs {
281ea6143a8SBen Skeggs switch (mthd) {
282ea6143a8SBen Skeggs case NVIF_OUTP_V0_RELEASE : return nvkm_uoutp_mthd_release (outp, argv, argc);
283f530bc60SBen Skeggs case NVIF_OUTP_V0_INFOFRAME : return nvkm_uoutp_mthd_infoframe (outp, argv, argc);
284a9f5d772SBen Skeggs case NVIF_OUTP_V0_HDA_ELD : return nvkm_uoutp_mthd_hda_eld (outp, argv, argc);
2858bb30c88SBen Skeggs case NVIF_OUTP_V0_DP_RETRAIN : return nvkm_uoutp_mthd_dp_retrain (outp, argv, argc);
2868c7d980dSBen Skeggs case NVIF_OUTP_V0_DP_MST_VCPI: return nvkm_uoutp_mthd_dp_mst_vcpi(outp, argv, argc);
287ea6143a8SBen Skeggs default:
288ea6143a8SBen Skeggs break;
289ea6143a8SBen Skeggs }
290ea6143a8SBen Skeggs
291ea6143a8SBen Skeggs return -EINVAL;
292ea6143a8SBen Skeggs }
293ea6143a8SBen Skeggs
294ea6143a8SBen Skeggs static int
nvkm_uoutp_mthd_noacquire(struct nvkm_outp * outp,u32 mthd,void * argv,u32 argc)2951b255f1cSBen Skeggs nvkm_uoutp_mthd_noacquire(struct nvkm_outp *outp, u32 mthd, void *argv, u32 argc)
2961b255f1cSBen Skeggs {
2971b255f1cSBen Skeggs switch (mthd) {
298dfc4005fSBen Skeggs case NVIF_OUTP_V0_LOAD_DETECT: return nvkm_uoutp_mthd_load_detect(outp, argv, argc);
299ea6143a8SBen Skeggs case NVIF_OUTP_V0_ACQUIRE : return nvkm_uoutp_mthd_acquire (outp, argv, argc);
300a62b7493SBen Skeggs case NVIF_OUTP_V0_DP_AUX_PWR : return nvkm_uoutp_mthd_dp_aux_pwr (outp, argv, argc);
3011b255f1cSBen Skeggs default:
3021b255f1cSBen Skeggs break;
3031b255f1cSBen Skeggs }
3041b255f1cSBen Skeggs
3051b255f1cSBen Skeggs return 1;
3061b255f1cSBen Skeggs }
3071b255f1cSBen Skeggs
3081b255f1cSBen Skeggs static int
nvkm_uoutp_mthd(struct nvkm_object * object,u32 mthd,void * argv,u32 argc)3091b255f1cSBen Skeggs nvkm_uoutp_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
3101b255f1cSBen Skeggs {
3111b255f1cSBen Skeggs struct nvkm_outp *outp = nvkm_uoutp(object);
3121b255f1cSBen Skeggs struct nvkm_disp *disp = outp->disp;
3131b255f1cSBen Skeggs int ret;
3141b255f1cSBen Skeggs
3151b255f1cSBen Skeggs mutex_lock(&disp->super.mutex);
3161b255f1cSBen Skeggs
3171b255f1cSBen Skeggs ret = nvkm_uoutp_mthd_noacquire(outp, mthd, argv, argc);
3181b255f1cSBen Skeggs if (ret <= 0)
3191b255f1cSBen Skeggs goto done;
3201b255f1cSBen Skeggs
321ea6143a8SBen Skeggs if (outp->ior)
322ea6143a8SBen Skeggs ret = nvkm_uoutp_mthd_acquired(outp, mthd, argv, argc);
323ea6143a8SBen Skeggs else
324ea6143a8SBen Skeggs ret = -EIO;
325ea6143a8SBen Skeggs
3261b255f1cSBen Skeggs done:
3271b255f1cSBen Skeggs mutex_unlock(&disp->super.mutex);
3281b255f1cSBen Skeggs return ret;
3291b255f1cSBen Skeggs }
3301b255f1cSBen Skeggs
3311b255f1cSBen Skeggs static void *
nvkm_uoutp_dtor(struct nvkm_object * object)3321b255f1cSBen Skeggs nvkm_uoutp_dtor(struct nvkm_object *object)
3331b255f1cSBen Skeggs {
3341b255f1cSBen Skeggs struct nvkm_outp *outp = nvkm_uoutp(object);
3351b255f1cSBen Skeggs struct nvkm_disp *disp = outp->disp;
3361b255f1cSBen Skeggs
3371b255f1cSBen Skeggs spin_lock(&disp->client.lock);
3381b255f1cSBen Skeggs outp->object.func = NULL;
3391b255f1cSBen Skeggs spin_unlock(&disp->client.lock);
3401b255f1cSBen Skeggs return NULL;
3411b255f1cSBen Skeggs }
3421b255f1cSBen Skeggs
3431b255f1cSBen Skeggs static const struct nvkm_object_func
3441b255f1cSBen Skeggs nvkm_uoutp = {
3451b255f1cSBen Skeggs .dtor = nvkm_uoutp_dtor,
3461b255f1cSBen Skeggs .mthd = nvkm_uoutp_mthd,
3471b255f1cSBen Skeggs };
3481b255f1cSBen Skeggs
3491b255f1cSBen Skeggs int
nvkm_uoutp_new(const struct nvkm_oclass * oclass,void * argv,u32 argc,struct nvkm_object ** pobject)3501b255f1cSBen Skeggs nvkm_uoutp_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, struct nvkm_object **pobject)
3511b255f1cSBen Skeggs {
3521b255f1cSBen Skeggs struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
3531b255f1cSBen Skeggs struct nvkm_outp *outt, *outp = NULL;
3541b255f1cSBen Skeggs union nvif_outp_args *args = argv;
3551b255f1cSBen Skeggs int ret;
3561b255f1cSBen Skeggs
3571b255f1cSBen Skeggs if (argc != sizeof(args->v0) || args->v0.version != 0)
3581b255f1cSBen Skeggs return -ENOSYS;
3591b255f1cSBen Skeggs
3601b255f1cSBen Skeggs list_for_each_entry(outt, &disp->outps, head) {
3611b255f1cSBen Skeggs if (outt->index == args->v0.id) {
3621b255f1cSBen Skeggs outp = outt;
3631b255f1cSBen Skeggs break;
3641b255f1cSBen Skeggs }
3651b255f1cSBen Skeggs }
3661b255f1cSBen Skeggs
3671b255f1cSBen Skeggs if (!outp)
3681b255f1cSBen Skeggs return -EINVAL;
3691b255f1cSBen Skeggs
3701b255f1cSBen Skeggs ret = -EBUSY;
3711b255f1cSBen Skeggs spin_lock(&disp->client.lock);
3721b255f1cSBen Skeggs if (!outp->object.func) {
3731b255f1cSBen Skeggs nvkm_object_ctor(&nvkm_uoutp, oclass, &outp->object);
3741b255f1cSBen Skeggs *pobject = &outp->object;
3751b255f1cSBen Skeggs ret = 0;
3761b255f1cSBen Skeggs }
3771b255f1cSBen Skeggs spin_unlock(&disp->client.lock);
3781b255f1cSBen Skeggs return ret;
3791b255f1cSBen Skeggs }
380