Home | History | Annotate | Line # | Download | only in disp
      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
     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
    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
    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 *
    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
    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
    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