xref: /linux/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/disp.c (revision 7b1166dee847d5018c1f3cc781218e806078f752)
19e994444SBen Skeggs /*
29e994444SBen Skeggs  * Copyright 2023 Red Hat Inc.
39e994444SBen Skeggs  *
49e994444SBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
59e994444SBen Skeggs  * copy of this software and associated documentation files (the "Software"),
69e994444SBen Skeggs  * to deal in the Software without restriction, including without limitation
79e994444SBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
89e994444SBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
99e994444SBen Skeggs  * Software is furnished to do so, subject to the following conditions:
109e994444SBen Skeggs  *
119e994444SBen Skeggs  * The above copyright notice and this permission notice shall be included in
129e994444SBen Skeggs  * all copies or substantial portions of the Software.
139e994444SBen Skeggs  *
149e994444SBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
159e994444SBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169e994444SBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
179e994444SBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
189e994444SBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
199e994444SBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
209e994444SBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
219e994444SBen Skeggs  */
22c472d828SBen Skeggs #include <engine/disp/priv.h>
23c472d828SBen Skeggs #include <engine/disp/chan.h>
24c472d828SBen Skeggs #include <engine/disp/conn.h>
25c472d828SBen Skeggs #include <engine/disp/dp.h>
26c472d828SBen Skeggs #include <engine/disp/head.h>
27c472d828SBen Skeggs #include <engine/disp/ior.h>
28c472d828SBen Skeggs #include <engine/disp/outp.h>
299e994444SBen Skeggs 
309e994444SBen Skeggs #include <core/ramht.h>
319e994444SBen Skeggs #include <subdev/bios.h>
329e994444SBen Skeggs #include <subdev/bios/conn.h>
339e994444SBen Skeggs #include <subdev/gsp.h>
349e994444SBen Skeggs #include <subdev/mmu.h>
359e994444SBen Skeggs #include <subdev/vfn.h>
369e994444SBen Skeggs 
370fac5141SBen Skeggs #include <rm/gpu.h>
380fac5141SBen Skeggs 
399e994444SBen Skeggs #include <nvhw/drf.h>
409e994444SBen Skeggs 
410c6aa94fSBen Skeggs #include "nvrm/disp.h"
429e994444SBen Skeggs 
439e994444SBen Skeggs #include <linux/acpi.h>
449e994444SBen Skeggs 
459e994444SBen Skeggs static u64
r535_chan_user(struct nvkm_disp_chan * chan,u64 * psize)469e994444SBen Skeggs r535_chan_user(struct nvkm_disp_chan *chan, u64 *psize)
479e994444SBen Skeggs {
489e994444SBen Skeggs 	switch (chan->object.oclass & 0xff) {
499e994444SBen Skeggs 	case 0x7d: *psize = 0x10000; return 0x680000;
509e994444SBen Skeggs 	case 0x7e: *psize = 0x01000; return 0x690000 + (chan->head * *psize);
519e994444SBen Skeggs 	case 0x7b: *psize = 0x01000; return 0x6b0000 + (chan->head * *psize);
529e994444SBen Skeggs 	case 0x7a: *psize = 0x01000; return 0x6d8000 + (chan->head * *psize);
539e994444SBen Skeggs 	default:
549e994444SBen Skeggs 		BUG_ON(1);
559e994444SBen Skeggs 		break;
569e994444SBen Skeggs 	}
579e994444SBen Skeggs 
589e994444SBen Skeggs 	return 0ULL;
599e994444SBen Skeggs }
609e994444SBen Skeggs 
619e994444SBen Skeggs static void
r535_chan_intr(struct nvkm_disp_chan * chan,bool en)629e994444SBen Skeggs r535_chan_intr(struct nvkm_disp_chan *chan, bool en)
639e994444SBen Skeggs {
649e994444SBen Skeggs }
659e994444SBen Skeggs 
669e994444SBen Skeggs static void
r535_chan_fini(struct nvkm_disp_chan * chan)679e994444SBen Skeggs r535_chan_fini(struct nvkm_disp_chan *chan)
689e994444SBen Skeggs {
699e994444SBen Skeggs 	nvkm_gsp_rm_free(&chan->rm.object);
709e994444SBen Skeggs }
719e994444SBen Skeggs 
729e994444SBen Skeggs static int
r535_disp_chan_set_pushbuf(struct nvkm_disp * disp,s32 oclass,int inst,struct nvkm_memory * memory)73e0ed9434SBen Skeggs r535_disp_chan_set_pushbuf(struct nvkm_disp *disp, s32 oclass, int inst, struct nvkm_memory *memory)
749e994444SBen Skeggs {
75e0ed9434SBen Skeggs 	struct nvkm_gsp *gsp = disp->rm.objcom.client->gsp;
769e994444SBen Skeggs 	NV2080_CTRL_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER_PARAMS *ctrl;
779e994444SBen Skeggs 
789e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,
799e994444SBen Skeggs 				    NV2080_CTRL_CMD_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER,
809e994444SBen Skeggs 				    sizeof(*ctrl));
819e994444SBen Skeggs 	if (IS_ERR(ctrl))
829e994444SBen Skeggs 		return PTR_ERR(ctrl);
839e994444SBen Skeggs 
84e0ed9434SBen Skeggs 	if (memory) {
85e0ed9434SBen Skeggs 		switch (nvkm_memory_target(memory)) {
869e994444SBen Skeggs 		case NVKM_MEM_TARGET_NCOH:
879e994444SBen Skeggs 			ctrl->addressSpace = ADDR_SYSMEM;
889e994444SBen Skeggs 			ctrl->cacheSnoop = 0;
899e994444SBen Skeggs 			break;
909e994444SBen Skeggs 		case NVKM_MEM_TARGET_HOST:
919e994444SBen Skeggs 			ctrl->addressSpace = ADDR_SYSMEM;
929e994444SBen Skeggs 			ctrl->cacheSnoop = 1;
939e994444SBen Skeggs 			break;
949e994444SBen Skeggs 		case NVKM_MEM_TARGET_VRAM:
959e994444SBen Skeggs 			ctrl->addressSpace = ADDR_FBMEM;
969e994444SBen Skeggs 			break;
979e994444SBen Skeggs 		default:
989e994444SBen Skeggs 			WARN_ON(1);
999e994444SBen Skeggs 			return -EINVAL;
1009e994444SBen Skeggs 		}
1019e994444SBen Skeggs 
102e0ed9434SBen Skeggs 		ctrl->physicalAddr = nvkm_memory_addr(memory);
103e0ed9434SBen Skeggs 		ctrl->limit = nvkm_memory_size(memory) - 1;
1049e994444SBen Skeggs 	}
1059e994444SBen Skeggs 
106e0ed9434SBen Skeggs 	ctrl->hclass = oclass;
107e0ed9434SBen Skeggs 	ctrl->channelInstance = inst;
108e0ed9434SBen Skeggs 	ctrl->valid = ((oclass & 0xff) != 0x7a) ? 1 : 0;
1099e994444SBen Skeggs 
1109e994444SBen Skeggs 	return nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
1119e994444SBen Skeggs }
1129e994444SBen Skeggs 
1139e994444SBen Skeggs static int
r535_curs_init(struct nvkm_disp_chan * chan)1149e994444SBen Skeggs r535_curs_init(struct nvkm_disp_chan *chan)
1159e994444SBen Skeggs {
116e0ed9434SBen Skeggs 	const struct nvkm_rm_api *rmapi = chan->disp->rm.objcom.client->gsp->rm->api;
1179e994444SBen Skeggs 	NV50VAIO_CHANNELPIO_ALLOCATION_PARAMETERS *args;
1189e994444SBen Skeggs 	int ret;
1199e994444SBen Skeggs 
120e0ed9434SBen Skeggs 	ret = rmapi->disp->chan.set_pushbuf(chan->disp, chan->object.oclass, chan->head, NULL);
1219e994444SBen Skeggs 	if (ret)
1229e994444SBen Skeggs 		return ret;
1239e994444SBen Skeggs 
1249e994444SBen Skeggs 	args = nvkm_gsp_rm_alloc_get(&chan->disp->rm.object,
1259e994444SBen Skeggs 				     (chan->object.oclass << 16) | chan->head,
1269e994444SBen Skeggs 				     chan->object.oclass, sizeof(*args), &chan->rm.object);
1279e994444SBen Skeggs 	if (IS_ERR(args))
1289e994444SBen Skeggs 		return PTR_ERR(args);
1299e994444SBen Skeggs 
1309e994444SBen Skeggs 	args->channelInstance = chan->head;
1319e994444SBen Skeggs 
1329e994444SBen Skeggs 	return nvkm_gsp_rm_alloc_wr(&chan->rm.object, args);
1339e994444SBen Skeggs }
1349e994444SBen Skeggs 
1359e994444SBen Skeggs static const struct nvkm_disp_chan_func
1369e994444SBen Skeggs r535_curs_func = {
1379e994444SBen Skeggs 	.init = r535_curs_init,
1389e994444SBen Skeggs 	.fini = r535_chan_fini,
1399e994444SBen Skeggs 	.intr = r535_chan_intr,
1409e994444SBen Skeggs 	.user = r535_chan_user,
1419e994444SBen Skeggs };
1429e994444SBen Skeggs 
1439e994444SBen Skeggs static const struct nvkm_disp_chan_user
1449e994444SBen Skeggs r535_curs = {
1459e994444SBen Skeggs 	.func = &r535_curs_func,
1469e994444SBen Skeggs 	.user = 73,
1479e994444SBen Skeggs };
1489e994444SBen Skeggs 
1499e994444SBen Skeggs static int
r535_dmac_bind(struct nvkm_disp_chan * chan,struct nvkm_object * object,u32 handle)1509e994444SBen Skeggs r535_dmac_bind(struct nvkm_disp_chan *chan, struct nvkm_object *object, u32 handle)
1519e994444SBen Skeggs {
1529e994444SBen Skeggs 	return nvkm_ramht_insert(chan->disp->ramht, object, chan->chid.user, -9, handle,
1539e994444SBen Skeggs 				 chan->chid.user << 25 |
1549e994444SBen Skeggs 				 (chan->disp->rm.client.object.handle & 0x3fff));
1559e994444SBen Skeggs }
1569e994444SBen Skeggs 
1579e994444SBen Skeggs static void
r535_dmac_fini(struct nvkm_disp_chan * chan)1589e994444SBen Skeggs r535_dmac_fini(struct nvkm_disp_chan *chan)
1599e994444SBen Skeggs {
1609e994444SBen Skeggs 	struct nvkm_device *device = chan->disp->engine.subdev.device;
1619e994444SBen Skeggs 	const u32 uoff = (chan->chid.user - 1) * 0x1000;
1629e994444SBen Skeggs 
1639e994444SBen Skeggs 	chan->suspend_put = nvkm_rd32(device, 0x690000 + uoff);
1649e994444SBen Skeggs 	r535_chan_fini(chan);
1659e994444SBen Skeggs }
1669e994444SBen Skeggs 
1679e994444SBen Skeggs static int
r535_dmac_alloc(struct nvkm_disp * disp,u32 oclass,int inst,u32 put_offset,struct nvkm_gsp_object * dmac)168*f82fb646SBen Skeggs r535_dmac_alloc(struct nvkm_disp *disp, u32 oclass, int inst, u32 put_offset,
169*f82fb646SBen Skeggs 		struct nvkm_gsp_object *dmac)
1709e994444SBen Skeggs {
1719e994444SBen Skeggs 	NV50VAIO_CHANNELDMA_ALLOCATION_PARAMETERS *args;
1729e994444SBen Skeggs 
173*f82fb646SBen Skeggs 	args = nvkm_gsp_rm_alloc_get(&disp->rm.object, (oclass << 16) | inst, oclass,
174*f82fb646SBen Skeggs 				     sizeof(*args), dmac);
1759e994444SBen Skeggs 	if (IS_ERR(args))
1769e994444SBen Skeggs 		return PTR_ERR(args);
1779e994444SBen Skeggs 
178*f82fb646SBen Skeggs 	args->channelInstance = inst;
179*f82fb646SBen Skeggs 	args->offset = put_offset;
1809e994444SBen Skeggs 
181*f82fb646SBen Skeggs 	return nvkm_gsp_rm_alloc_wr(dmac, args);
182*f82fb646SBen Skeggs }
183*f82fb646SBen Skeggs 
184*f82fb646SBen Skeggs static int
r535_dmac_init(struct nvkm_disp_chan * chan)1859e994444SBen Skeggs r535_dmac_init(struct nvkm_disp_chan *chan)
1869e994444SBen Skeggs {
187e0ed9434SBen Skeggs 	const struct nvkm_rm_api *rmapi = chan->disp->rm.objcom.client->gsp->rm->api;
1889e994444SBen Skeggs 	int ret;
1899e994444SBen Skeggs 
190e0ed9434SBen Skeggs 	ret = rmapi->disp->chan.set_pushbuf(chan->disp, chan->object.oclass, chan->head, chan->memory);
1919e994444SBen Skeggs 	if (ret)
1929e994444SBen Skeggs 		return ret;
1939e994444SBen Skeggs 
194*f82fb646SBen Skeggs 	return rmapi->disp->chan.dmac_alloc(chan->disp, chan->object.oclass, chan->head,
195*f82fb646SBen Skeggs 					    chan->suspend_put, &chan->rm.object);
1969e994444SBen Skeggs }
1979e994444SBen Skeggs 
1989e994444SBen Skeggs static int
r535_dmac_push(struct nvkm_disp_chan * chan,u64 memory)1999e994444SBen Skeggs r535_dmac_push(struct nvkm_disp_chan *chan, u64 memory)
2009e994444SBen Skeggs {
2019e994444SBen Skeggs 	chan->memory = nvkm_umem_search(chan->object.client, memory);
2029e994444SBen Skeggs 	if (IS_ERR(chan->memory))
2039e994444SBen Skeggs 		return PTR_ERR(chan->memory);
2049e994444SBen Skeggs 
2059e994444SBen Skeggs 	return 0;
2069e994444SBen Skeggs }
2079e994444SBen Skeggs 
2089e994444SBen Skeggs static const struct nvkm_disp_chan_func
2099e994444SBen Skeggs r535_dmac_func = {
2109e994444SBen Skeggs 	.push = r535_dmac_push,
2119e994444SBen Skeggs 	.init = r535_dmac_init,
2129e994444SBen Skeggs 	.fini = r535_dmac_fini,
2139e994444SBen Skeggs 	.intr = r535_chan_intr,
2149e994444SBen Skeggs 	.user = r535_chan_user,
2159e994444SBen Skeggs 	.bind = r535_dmac_bind,
2169e994444SBen Skeggs };
2179e994444SBen Skeggs 
2189e994444SBen Skeggs static const struct nvkm_disp_chan_func
2199e994444SBen Skeggs r535_wimm_func = {
2209e994444SBen Skeggs 	.push = r535_dmac_push,
2219e994444SBen Skeggs 	.init = r535_dmac_init,
2229e994444SBen Skeggs 	.fini = r535_dmac_fini,
2239e994444SBen Skeggs 	.intr = r535_chan_intr,
2249e994444SBen Skeggs 	.user = r535_chan_user,
2259e994444SBen Skeggs };
2269e994444SBen Skeggs 
2279e994444SBen Skeggs static const struct nvkm_disp_chan_user
2289e994444SBen Skeggs r535_wimm = {
2299e994444SBen Skeggs 	.func = &r535_wimm_func,
2309e994444SBen Skeggs 	.user = 33,
2319e994444SBen Skeggs };
2329e994444SBen Skeggs 
2339e994444SBen Skeggs static const struct nvkm_disp_chan_user
2349e994444SBen Skeggs r535_wndw = {
2359e994444SBen Skeggs 	.func = &r535_dmac_func,
2369e994444SBen Skeggs 	.user = 1,
2379e994444SBen Skeggs };
2389e994444SBen Skeggs 
2399e994444SBen Skeggs static void
r535_core_fini(struct nvkm_disp_chan * chan)2409e994444SBen Skeggs r535_core_fini(struct nvkm_disp_chan *chan)
2419e994444SBen Skeggs {
2429e994444SBen Skeggs 	struct nvkm_device *device = chan->disp->engine.subdev.device;
2439e994444SBen Skeggs 
2449e994444SBen Skeggs 	chan->suspend_put = nvkm_rd32(device, 0x680000);
2459e994444SBen Skeggs 	r535_chan_fini(chan);
2469e994444SBen Skeggs }
2479e994444SBen Skeggs 
2489e994444SBen Skeggs static const struct nvkm_disp_chan_func
2499e994444SBen Skeggs r535_core_func = {
2509e994444SBen Skeggs 	.push = r535_dmac_push,
2519e994444SBen Skeggs 	.init = r535_dmac_init,
2529e994444SBen Skeggs 	.fini = r535_core_fini,
2539e994444SBen Skeggs 	.intr = r535_chan_intr,
2549e994444SBen Skeggs 	.user = r535_chan_user,
2559e994444SBen Skeggs 	.bind = r535_dmac_bind,
2569e994444SBen Skeggs };
2579e994444SBen Skeggs 
2589e994444SBen Skeggs static const struct nvkm_disp_chan_user
2599e994444SBen Skeggs r535_core = {
2609e994444SBen Skeggs 	.func = &r535_core_func,
2619e994444SBen Skeggs 	.user = 0,
2629e994444SBen Skeggs };
2639e994444SBen Skeggs 
2649e994444SBen Skeggs static int
r535_bl_ctrl(struct nvkm_disp * disp,unsigned display_id,bool set,int * pval)2658f8d9bcaSBen Skeggs r535_bl_ctrl(struct nvkm_disp *disp, unsigned display_id, bool set, int *pval)
2669e994444SBen Skeggs {
2678f8d9bcaSBen Skeggs 	u32 cmd = set ? NV0073_CTRL_CMD_SPECIFIC_SET_BACKLIGHT_BRIGHTNESS :
2688f8d9bcaSBen Skeggs 			NV0073_CTRL_CMD_SPECIFIC_GET_BACKLIGHT_BRIGHTNESS;
2699e994444SBen Skeggs 	NV0073_CTRL_SPECIFIC_BACKLIGHT_BRIGHTNESS_PARAMS *ctrl;
2708f8d9bcaSBen Skeggs 	int ret;
2719e994444SBen Skeggs 
2728f8d9bcaSBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, cmd, sizeof(*ctrl));
2739e994444SBen Skeggs 	if (IS_ERR(ctrl))
2749e994444SBen Skeggs 		return PTR_ERR(ctrl);
2759e994444SBen Skeggs 
2768f8d9bcaSBen Skeggs 	ctrl->displayId = BIT(display_id);
2778f8d9bcaSBen Skeggs 	ctrl->brightness = *pval;
2789e994444SBen Skeggs 
2798f8d9bcaSBen Skeggs 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
2808f8d9bcaSBen Skeggs 	if (ret)
2818f8d9bcaSBen Skeggs 		return ret;
2828f8d9bcaSBen Skeggs 
2838f8d9bcaSBen Skeggs 	*pval = ctrl->brightness;
2848f8d9bcaSBen Skeggs 
2858f8d9bcaSBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
2868f8d9bcaSBen Skeggs 	return 0;
2878f8d9bcaSBen Skeggs }
2888f8d9bcaSBen Skeggs 
2898f8d9bcaSBen Skeggs static int
r535_sor_bl_set(struct nvkm_ior * sor,int lvl)2908f8d9bcaSBen Skeggs r535_sor_bl_set(struct nvkm_ior *sor, int lvl)
2918f8d9bcaSBen Skeggs {
2928f8d9bcaSBen Skeggs 	struct nvkm_disp *disp = sor->disp;
2938f8d9bcaSBen Skeggs 	const struct nvkm_rm_api *rmapi = disp->engine.subdev.device->gsp->rm->api;
2948f8d9bcaSBen Skeggs 
2958f8d9bcaSBen Skeggs 	return rmapi->disp->bl_ctrl(disp, sor->asy.outp->index, true, &lvl);
2969e994444SBen Skeggs }
2979e994444SBen Skeggs 
2989e994444SBen Skeggs static int
r535_sor_bl_get(struct nvkm_ior * sor)2999e994444SBen Skeggs r535_sor_bl_get(struct nvkm_ior *sor)
3009e994444SBen Skeggs {
3019e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
3028f8d9bcaSBen Skeggs 	const struct nvkm_rm_api *rmapi = disp->engine.subdev.device->gsp->rm->api;
3038f8d9bcaSBen Skeggs 	int lvl, ret = rmapi->disp->bl_ctrl(disp, sor->asy.outp->index, false, &lvl);
3049e994444SBen Skeggs 
3058f8d9bcaSBen Skeggs 	return (ret == 0) ? lvl : ret;
3069e994444SBen Skeggs }
3079e994444SBen Skeggs 
3089e994444SBen Skeggs static const struct nvkm_ior_func_bl
3099e994444SBen Skeggs r535_sor_bl = {
3109e994444SBen Skeggs 	.get = r535_sor_bl_get,
3119e994444SBen Skeggs 	.set = r535_sor_bl_set,
3129e994444SBen Skeggs };
3139e994444SBen Skeggs 
3149e994444SBen Skeggs static void
r535_sor_hda_eld(struct nvkm_ior * sor,int head,u8 * data,u8 size)3159e994444SBen Skeggs r535_sor_hda_eld(struct nvkm_ior *sor, int head, u8 *data, u8 size)
3169e994444SBen Skeggs {
3179e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
3189e994444SBen Skeggs 	NV0073_CTRL_DFP_SET_ELD_AUDIO_CAP_PARAMS *ctrl;
3199e994444SBen Skeggs 
3209e994444SBen Skeggs 	if (WARN_ON(size > sizeof(ctrl->bufferELD)))
3219e994444SBen Skeggs 		return;
3229e994444SBen Skeggs 
3239e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
3249e994444SBen Skeggs 				    NV0073_CTRL_CMD_DFP_SET_ELD_AUDIO_CAPS, sizeof(*ctrl));
3259e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
3269e994444SBen Skeggs 		return;
3279e994444SBen Skeggs 
3289e994444SBen Skeggs 	ctrl->displayId = BIT(sor->asy.outp->index);
3299e994444SBen Skeggs 	ctrl->numELDSize = size;
3309e994444SBen Skeggs 	memcpy(ctrl->bufferELD, data, size);
3319e994444SBen Skeggs 	ctrl->maxFreqSupported = 0; //XXX
3329e994444SBen Skeggs 	ctrl->ctrl  = NVDEF(NV0073, CTRL_DFP_ELD_AUDIO_CAPS_CTRL, PD, TRUE);
3339e994444SBen Skeggs 	ctrl->ctrl |= NVDEF(NV0073, CTRL_DFP_ELD_AUDIO_CAPS_CTRL, ELDV, TRUE);
3349e994444SBen Skeggs 	ctrl->deviceEntry = head;
3359e994444SBen Skeggs 
3369e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
3379e994444SBen Skeggs }
3389e994444SBen Skeggs 
3399e994444SBen Skeggs static void
r535_sor_hda_hpd(struct nvkm_ior * sor,int head,bool present)3409e994444SBen Skeggs r535_sor_hda_hpd(struct nvkm_ior *sor, int head, bool present)
3419e994444SBen Skeggs {
3429e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
3439e994444SBen Skeggs 	NV0073_CTRL_DFP_SET_ELD_AUDIO_CAP_PARAMS *ctrl;
3449e994444SBen Skeggs 
3459e994444SBen Skeggs 	if (present)
3469e994444SBen Skeggs 		return;
3479e994444SBen Skeggs 
3489e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
3499e994444SBen Skeggs 				    NV0073_CTRL_CMD_DFP_SET_ELD_AUDIO_CAPS, sizeof(*ctrl));
3509e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
3519e994444SBen Skeggs 		return;
3529e994444SBen Skeggs 
3539e994444SBen Skeggs 	ctrl->displayId = BIT(sor->asy.outp->index);
3549e994444SBen Skeggs 	ctrl->deviceEntry = head;
3559e994444SBen Skeggs 
3569e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
3579e994444SBen Skeggs }
3589e994444SBen Skeggs 
3599e994444SBen Skeggs static const struct nvkm_ior_func_hda
3609e994444SBen Skeggs r535_sor_hda = {
3619e994444SBen Skeggs 	.hpd = r535_sor_hda_hpd,
3629e994444SBen Skeggs 	.eld = r535_sor_hda_eld,
3639e994444SBen Skeggs };
3649e994444SBen Skeggs 
3659e994444SBen Skeggs static void
r535_sor_dp_audio_mute(struct nvkm_ior * sor,bool mute)3669e994444SBen Skeggs r535_sor_dp_audio_mute(struct nvkm_ior *sor, bool mute)
3679e994444SBen Skeggs {
3689e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
3699e994444SBen Skeggs 	NV0073_CTRL_DP_SET_AUDIO_MUTESTREAM_PARAMS *ctrl;
3709e994444SBen Skeggs 
3719e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
3729e994444SBen Skeggs 				    NV0073_CTRL_CMD_DP_SET_AUDIO_MUTESTREAM, sizeof(*ctrl));
3739e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
3749e994444SBen Skeggs 		return;
3759e994444SBen Skeggs 
3769e994444SBen Skeggs 	ctrl->displayId = BIT(sor->asy.outp->index);
3779e994444SBen Skeggs 	ctrl->mute = mute;
3789e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
3799e994444SBen Skeggs }
3809e994444SBen Skeggs 
3819e994444SBen Skeggs static void
r535_sor_dp_audio(struct nvkm_ior * sor,int head,bool enable)3829e994444SBen Skeggs r535_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)
3839e994444SBen Skeggs {
3849e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
3859e994444SBen Skeggs 	NV0073_CTRL_DFP_SET_AUDIO_ENABLE_PARAMS *ctrl;
3869e994444SBen Skeggs 
3879e994444SBen Skeggs 	if (!enable)
3889e994444SBen Skeggs 		r535_sor_dp_audio_mute(sor, true);
3899e994444SBen Skeggs 
3909e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
3919e994444SBen Skeggs 				    NV0073_CTRL_CMD_DFP_SET_AUDIO_ENABLE, sizeof(*ctrl));
3929e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
3939e994444SBen Skeggs 		return;
3949e994444SBen Skeggs 
3959e994444SBen Skeggs 	ctrl->displayId = BIT(sor->asy.outp->index);
3969e994444SBen Skeggs 	ctrl->enable = enable;
3979e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
3989e994444SBen Skeggs 
3999e994444SBen Skeggs 	if (enable)
4009e994444SBen Skeggs 		r535_sor_dp_audio_mute(sor, false);
4019e994444SBen Skeggs }
4029e994444SBen Skeggs 
4039e994444SBen Skeggs static void
r535_sor_dp_vcpi(struct nvkm_ior * sor,int head,u8 slot,u8 slot_nr,u16 pbn,u16 aligned_pbn)4049e994444SBen Skeggs r535_sor_dp_vcpi(struct nvkm_ior *sor, int head, u8 slot, u8 slot_nr, u16 pbn, u16 aligned_pbn)
4059e994444SBen Skeggs {
4069e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
4079e994444SBen Skeggs 	struct NV0073_CTRL_CMD_DP_CONFIG_STREAM_PARAMS *ctrl;
4089e994444SBen Skeggs 
4099e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
4109e994444SBen Skeggs 				    NV0073_CTRL_CMD_DP_CONFIG_STREAM, sizeof(*ctrl));
4119e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
4129e994444SBen Skeggs 		return;
4139e994444SBen Skeggs 
4149e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
4159e994444SBen Skeggs 	ctrl->head = head;
4169e994444SBen Skeggs 	ctrl->sorIndex = sor->id;
4179e994444SBen Skeggs 	ctrl->dpLink = sor->asy.link == 2;
4189e994444SBen Skeggs 	ctrl->bEnableOverride = 1;
4199e994444SBen Skeggs 	ctrl->bMST = 1;
4209e994444SBen Skeggs 	ctrl->hBlankSym = 0;
4219e994444SBen Skeggs 	ctrl->vBlankSym = 0;
4229e994444SBen Skeggs 	ctrl->colorFormat = 0;
4239e994444SBen Skeggs 	ctrl->bEnableTwoHeadOneOr = 0;
4249e994444SBen Skeggs 	ctrl->singleHeadMultistreamMode = 0;
4259e994444SBen Skeggs 	ctrl->MST.slotStart = slot;
4269e994444SBen Skeggs 	ctrl->MST.slotEnd = slot + slot_nr - 1;
4279e994444SBen Skeggs 	ctrl->MST.PBN = pbn;
4289e994444SBen Skeggs 	ctrl->MST.Timeslice = aligned_pbn;
4299e994444SBen Skeggs 	ctrl->MST.sendACT = 0;
4309e994444SBen Skeggs 	ctrl->MST.singleHeadMSTPipeline = 0;
4319e994444SBen Skeggs 	ctrl->MST.bEnableAudioOverRightPanel = 0;
4329e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
4339e994444SBen Skeggs }
4349e994444SBen Skeggs 
4359e994444SBen Skeggs static int
r535_sor_dp_sst(struct nvkm_ior * sor,int head,bool ef,u32 watermark,u32 hblanksym,u32 vblanksym)4369e994444SBen Skeggs r535_sor_dp_sst(struct nvkm_ior *sor, int head, bool ef,
4379e994444SBen Skeggs 		u32 watermark, u32 hblanksym, u32 vblanksym)
4389e994444SBen Skeggs {
4399e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
4409e994444SBen Skeggs 	struct NV0073_CTRL_CMD_DP_CONFIG_STREAM_PARAMS *ctrl;
4419e994444SBen Skeggs 
4429e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
4439e994444SBen Skeggs 				    NV0073_CTRL_CMD_DP_CONFIG_STREAM, sizeof(*ctrl));
4449e994444SBen Skeggs 	if (IS_ERR(ctrl))
4459e994444SBen Skeggs 		return PTR_ERR(ctrl);
4469e994444SBen Skeggs 
4479e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
4489e994444SBen Skeggs 	ctrl->head = head;
4499e994444SBen Skeggs 	ctrl->sorIndex = sor->id;
4509e994444SBen Skeggs 	ctrl->dpLink = sor->asy.link == 2;
4519e994444SBen Skeggs 	ctrl->bEnableOverride = 1;
4529e994444SBen Skeggs 	ctrl->bMST = 0;
4539e994444SBen Skeggs 	ctrl->hBlankSym = hblanksym;
4549e994444SBen Skeggs 	ctrl->vBlankSym = vblanksym;
4559e994444SBen Skeggs 	ctrl->colorFormat = 0;
4569e994444SBen Skeggs 	ctrl->bEnableTwoHeadOneOr = 0;
4579e994444SBen Skeggs 	ctrl->SST.bEnhancedFraming = ef;
4589e994444SBen Skeggs 	ctrl->SST.tuSize = 64;
4599e994444SBen Skeggs 	ctrl->SST.waterMark = watermark;
4609e994444SBen Skeggs 	ctrl->SST.bEnableAudioOverRightPanel = 0;
4619e994444SBen Skeggs 	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
4629e994444SBen Skeggs }
4639e994444SBen Skeggs 
4649e994444SBen Skeggs static const struct nvkm_ior_func_dp
4659e994444SBen Skeggs r535_sor_dp = {
4669e994444SBen Skeggs 	.sst = r535_sor_dp_sst,
4679e994444SBen Skeggs 	.vcpi = r535_sor_dp_vcpi,
4689e994444SBen Skeggs 	.audio = r535_sor_dp_audio,
4699e994444SBen Skeggs };
4709e994444SBen Skeggs 
4719e994444SBen Skeggs static void
r535_sor_hdmi_scdc(struct nvkm_ior * sor,u32 khz,bool support,bool scrambling,bool scrambling_low_rates)4729e994444SBen Skeggs r535_sor_hdmi_scdc(struct nvkm_ior *sor, u32 khz, bool support, bool scrambling,
4739e994444SBen Skeggs 		   bool scrambling_low_rates)
4749e994444SBen Skeggs {
4759e994444SBen Skeggs 	struct nvkm_outp *outp = sor->asy.outp;
4769e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
4779e994444SBen Skeggs 	NV0073_CTRL_SPECIFIC_SET_HDMI_SINK_CAPS_PARAMS *ctrl;
4789e994444SBen Skeggs 
4799e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
4809e994444SBen Skeggs 				    NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_SINK_CAPS, sizeof(*ctrl));
4819e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
4829e994444SBen Skeggs 		return;
4839e994444SBen Skeggs 
4849e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
4859e994444SBen Skeggs 	ctrl->caps = 0;
4869e994444SBen Skeggs 	if (support)
4879e994444SBen Skeggs 		ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, SCDC_SUPPORTED, TRUE);
4889e994444SBen Skeggs 	if (scrambling)
4899e994444SBen Skeggs 		ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, GT_340MHZ_CLOCK_SUPPORTED, TRUE);
4909e994444SBen Skeggs 	if (scrambling_low_rates)
4919e994444SBen Skeggs 		ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, LTE_340MHZ_SCRAMBLING_SUPPORTED, TRUE);
4929e994444SBen Skeggs 
4939e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
4949e994444SBen Skeggs }
4959e994444SBen Skeggs 
4969e994444SBen Skeggs static void
r535_sor_hdmi_ctrl_audio_mute(struct nvkm_outp * outp,bool mute)4979e994444SBen Skeggs r535_sor_hdmi_ctrl_audio_mute(struct nvkm_outp *outp, bool mute)
4989e994444SBen Skeggs {
4999e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
5009e994444SBen Skeggs 	NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_AUDIO_MUTESTREAM_PARAMS *ctrl;
5019e994444SBen Skeggs 
5029e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
5039e994444SBen Skeggs 				    NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_AUDIO_MUTESTREAM, sizeof(*ctrl));
5049e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
5059e994444SBen Skeggs 		return;
5069e994444SBen Skeggs 
5079e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
5089e994444SBen Skeggs 	ctrl->mute = mute;
5099e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
5109e994444SBen Skeggs }
5119e994444SBen Skeggs 
5129e994444SBen Skeggs static void
r535_sor_hdmi_ctrl_audio(struct nvkm_outp * outp,bool enable)5139e994444SBen Skeggs r535_sor_hdmi_ctrl_audio(struct nvkm_outp *outp, bool enable)
5149e994444SBen Skeggs {
5159e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
5169e994444SBen Skeggs 	NV0073_CTRL_SPECIFIC_SET_OD_PACKET_PARAMS *ctrl;
5179e994444SBen Skeggs 
5189e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
5199e994444SBen Skeggs 				    NV0073_CTRL_CMD_SPECIFIC_SET_OD_PACKET, sizeof(*ctrl));
5209e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
5219e994444SBen Skeggs 		return;
5229e994444SBen Skeggs 
5239e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
5249e994444SBen Skeggs 	ctrl->transmitControl =
5259e994444SBen Skeggs 		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, ENABLE, YES) |
5269e994444SBen Skeggs 		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, OTHER_FRAME, DISABLE) |
5279e994444SBen Skeggs 		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, SINGLE_FRAME, DISABLE) |
5289e994444SBen Skeggs 		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, ON_HBLANK, DISABLE) |
5299e994444SBen Skeggs 		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, VIDEO_FMT, SW_CONTROLLED) |
5309e994444SBen Skeggs 		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, RESERVED_LEGACY_MODE, NO);
5319e994444SBen Skeggs 	ctrl->packetSize = 10;
5329e994444SBen Skeggs 	ctrl->aPacket[0] = 0x03;
5339e994444SBen Skeggs 	ctrl->aPacket[1] = 0x00;
5349e994444SBen Skeggs 	ctrl->aPacket[2] = 0x00;
5359e994444SBen Skeggs 	ctrl->aPacket[3] = enable ? 0x10 : 0x01;
5369e994444SBen Skeggs 	ctrl->aPacket[4] = 0x00;
5379e994444SBen Skeggs 	ctrl->aPacket[5] = 0x00;
5389e994444SBen Skeggs 	ctrl->aPacket[6] = 0x00;
5399e994444SBen Skeggs 	ctrl->aPacket[7] = 0x00;
5409e994444SBen Skeggs 	ctrl->aPacket[8] = 0x00;
5419e994444SBen Skeggs 	ctrl->aPacket[9] = 0x00;
5429e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
5439e994444SBen Skeggs }
5449e994444SBen Skeggs 
5459e994444SBen Skeggs static void
r535_sor_hdmi_audio(struct nvkm_ior * sor,int head,bool enable)5469e994444SBen Skeggs r535_sor_hdmi_audio(struct nvkm_ior *sor, int head, bool enable)
5479e994444SBen Skeggs {
5489e994444SBen Skeggs 	struct nvkm_device *device = sor->disp->engine.subdev.device;
5499e994444SBen Skeggs 	const u32 hdmi = head * 0x400;
5509e994444SBen Skeggs 
5519e994444SBen Skeggs 	r535_sor_hdmi_ctrl_audio(sor->asy.outp, enable);
5529e994444SBen Skeggs 	r535_sor_hdmi_ctrl_audio_mute(sor->asy.outp, !enable);
5539e994444SBen Skeggs 
5549e994444SBen Skeggs 	/* General Control (GCP). */
5559e994444SBen Skeggs 	nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000000);
5569e994444SBen Skeggs 	nvkm_wr32(device, 0x6f00cc + hdmi, !enable ? 0x00000001 : 0x00000010);
5579e994444SBen Skeggs 	nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000001);
5589e994444SBen Skeggs }
5599e994444SBen Skeggs 
5609e994444SBen Skeggs static void
r535_sor_hdmi_ctrl(struct nvkm_ior * sor,int head,bool enable,u8 max_ac_packet,u8 rekey)5619e994444SBen Skeggs r535_sor_hdmi_ctrl(struct nvkm_ior *sor, int head, bool enable, u8 max_ac_packet, u8 rekey)
5629e994444SBen Skeggs {
5639e994444SBen Skeggs 	struct nvkm_disp *disp = sor->disp;
5649e994444SBen Skeggs 	NV0073_CTRL_SPECIFIC_SET_HDMI_ENABLE_PARAMS *ctrl;
5659e994444SBen Skeggs 
5669e994444SBen Skeggs 	if (!enable)
5679e994444SBen Skeggs 		return;
5689e994444SBen Skeggs 
5699e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
5709e994444SBen Skeggs 				    NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_ENABLE, sizeof(*ctrl));
5719e994444SBen Skeggs 	if (WARN_ON(IS_ERR(ctrl)))
5729e994444SBen Skeggs 		return;
5739e994444SBen Skeggs 
5749e994444SBen Skeggs 	ctrl->displayId = BIT(sor->asy.outp->index);
5759e994444SBen Skeggs 	ctrl->enable = enable;
5769e994444SBen Skeggs 
5779e994444SBen Skeggs 	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));
5789e994444SBen Skeggs }
5799e994444SBen Skeggs 
5809e994444SBen Skeggs static const struct nvkm_ior_func_hdmi
5819e994444SBen Skeggs r535_sor_hdmi = {
5829e994444SBen Skeggs 	.ctrl = r535_sor_hdmi_ctrl,
5839e994444SBen Skeggs 	.scdc = r535_sor_hdmi_scdc,
5849e994444SBen Skeggs 	/*TODO: SF_USER -> KMS. */
5859e994444SBen Skeggs 	.infoframe_avi = gv100_sor_hdmi_infoframe_avi,
5869e994444SBen Skeggs 	.infoframe_vsi = gv100_sor_hdmi_infoframe_vsi,
5879e994444SBen Skeggs 	.audio = r535_sor_hdmi_audio,
5889e994444SBen Skeggs };
5899e994444SBen Skeggs 
5909e994444SBen Skeggs static const struct nvkm_ior_func
5919e994444SBen Skeggs r535_sor = {
5929e994444SBen Skeggs 	.hdmi = &r535_sor_hdmi,
5939e994444SBen Skeggs 	.dp = &r535_sor_dp,
5949e994444SBen Skeggs 	.hda = &r535_sor_hda,
5959e994444SBen Skeggs 	.bl = &r535_sor_bl,
5969e994444SBen Skeggs };
5979e994444SBen Skeggs 
5989e994444SBen Skeggs static int
r535_sor_new(struct nvkm_disp * disp,int id)5999e994444SBen Skeggs r535_sor_new(struct nvkm_disp *disp, int id)
6009e994444SBen Skeggs {
6019e994444SBen Skeggs 	return nvkm_ior_new_(&r535_sor, disp, SOR, id, true/*XXX: hda cap*/);
6029e994444SBen Skeggs }
6039e994444SBen Skeggs 
6049e994444SBen Skeggs static int
r535_sor_cnt(struct nvkm_disp * disp,unsigned long * pmask)6059e994444SBen Skeggs r535_sor_cnt(struct nvkm_disp *disp, unsigned long *pmask)
6069e994444SBen Skeggs {
6079e994444SBen Skeggs 	*pmask = 0xf;
6089e994444SBen Skeggs 	return 4;
6099e994444SBen Skeggs }
6109e994444SBen Skeggs 
6119e994444SBen Skeggs static void
r535_head_vblank_put(struct nvkm_head * head)6129e994444SBen Skeggs r535_head_vblank_put(struct nvkm_head *head)
6139e994444SBen Skeggs {
6149e994444SBen Skeggs 	struct nvkm_device *device = head->disp->engine.subdev.device;
6159e994444SBen Skeggs 
6169e994444SBen Skeggs 	nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000002, 0x00000000);
6179e994444SBen Skeggs }
6189e994444SBen Skeggs 
6199e994444SBen Skeggs static void
r535_head_vblank_get(struct nvkm_head * head)6209e994444SBen Skeggs r535_head_vblank_get(struct nvkm_head *head)
6219e994444SBen Skeggs {
6229e994444SBen Skeggs 	struct nvkm_device *device = head->disp->engine.subdev.device;
6239e994444SBen Skeggs 
6249e994444SBen Skeggs 	nvkm_wr32(device, 0x611800 + (head->id * 4), 0x00000002);
6259e994444SBen Skeggs 	nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000002, 0x00000002);
6269e994444SBen Skeggs }
6279e994444SBen Skeggs 
6289e994444SBen Skeggs static void
r535_head_state(struct nvkm_head * head,struct nvkm_head_state * state)6299e994444SBen Skeggs r535_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
6309e994444SBen Skeggs {
6319e994444SBen Skeggs }
6329e994444SBen Skeggs 
6339e994444SBen Skeggs static const struct nvkm_head_func
6349e994444SBen Skeggs r535_head = {
6359e994444SBen Skeggs 	.state = r535_head_state,
6369e994444SBen Skeggs 	.vblank_get = r535_head_vblank_get,
6379e994444SBen Skeggs 	.vblank_put = r535_head_vblank_put,
6389e994444SBen Skeggs };
6399e994444SBen Skeggs 
6409e994444SBen Skeggs static struct nvkm_conn *
r535_conn_new(struct nvkm_disp * disp,u32 id)6419e994444SBen Skeggs r535_conn_new(struct nvkm_disp *disp, u32 id)
6429e994444SBen Skeggs {
6439e994444SBen Skeggs 	NV0073_CTRL_SPECIFIC_GET_CONNECTOR_DATA_PARAMS *ctrl;
6449e994444SBen Skeggs 	struct nvbios_connE dcbE = {};
6459e994444SBen Skeggs 	struct nvkm_conn *conn;
6469e994444SBen Skeggs 	int ret, index;
6479e994444SBen Skeggs 
6489e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
6499e994444SBen Skeggs 				    NV0073_CTRL_CMD_SPECIFIC_GET_CONNECTOR_DATA, sizeof(*ctrl));
6509e994444SBen Skeggs 	if (IS_ERR(ctrl))
65101738c4fSZhang Enpei 		return ERR_CAST(ctrl);
6529e994444SBen Skeggs 
6539e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
6549e994444SBen Skeggs 	ctrl->displayId = BIT(id);
6559e994444SBen Skeggs 
6564ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
6574ae3a201SDave Airlie 	if (ret) {
6584ae3a201SDave Airlie 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
6594ae3a201SDave Airlie 		return ERR_PTR(ret);
6604ae3a201SDave Airlie 	}
6619e994444SBen Skeggs 
6629e994444SBen Skeggs 	list_for_each_entry(conn, &disp->conns, head) {
6639e994444SBen Skeggs 		if (conn->index == ctrl->data[0].index) {
6649e994444SBen Skeggs 			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
6659e994444SBen Skeggs 			return conn;
6669e994444SBen Skeggs 		}
6679e994444SBen Skeggs 	}
6689e994444SBen Skeggs 
6699e994444SBen Skeggs 	dcbE.type = ctrl->data[0].type;
6709e994444SBen Skeggs 	index = ctrl->data[0].index;
6719e994444SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
6729e994444SBen Skeggs 
6739e994444SBen Skeggs 	ret = nvkm_conn_new(disp, index, &dcbE, &conn);
6749e994444SBen Skeggs 	if (ret)
6759e994444SBen Skeggs 		return ERR_PTR(ret);
6769e994444SBen Skeggs 
6779e994444SBen Skeggs 	list_add_tail(&conn->head, &disp->conns);
6789e994444SBen Skeggs 	return conn;
6799e994444SBen Skeggs }
6809e994444SBen Skeggs 
6819e994444SBen Skeggs static void
r535_outp_release(struct nvkm_outp * outp)6829e994444SBen Skeggs r535_outp_release(struct nvkm_outp *outp)
6839e994444SBen Skeggs {
6849e994444SBen Skeggs 	outp->disp->rm.assigned_sors &= ~BIT(outp->ior->id);
6859e994444SBen Skeggs 	outp->ior->asy.outp = NULL;
6869e994444SBen Skeggs 	outp->ior = NULL;
6879e994444SBen Skeggs }
6889e994444SBen Skeggs 
6899e994444SBen Skeggs static int
r535_outp_acquire(struct nvkm_outp * outp,bool hda)6909e994444SBen Skeggs r535_outp_acquire(struct nvkm_outp *outp, bool hda)
6919e994444SBen Skeggs {
6929e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
6939e994444SBen Skeggs 	struct nvkm_ior *ior;
6949e994444SBen Skeggs 	NV0073_CTRL_DFP_ASSIGN_SOR_PARAMS *ctrl;
6954ae3a201SDave Airlie 	int ret, or;
6969e994444SBen Skeggs 
6979e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
6989e994444SBen Skeggs 				    NV0073_CTRL_CMD_DFP_ASSIGN_SOR, sizeof(*ctrl));
6999e994444SBen Skeggs 	if (IS_ERR(ctrl))
7009e994444SBen Skeggs 		return PTR_ERR(ctrl);
7019e994444SBen Skeggs 
7029e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
7039e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
7049e994444SBen Skeggs 	ctrl->sorExcludeMask = disp->rm.assigned_sors;
7059e994444SBen Skeggs 	if (hda)
7069e994444SBen Skeggs 		ctrl->flags |= NVDEF(NV0073_CTRL, DFP_ASSIGN_SOR_FLAGS, AUDIO, OPTIMAL);
7079e994444SBen Skeggs 
7084ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
7094ae3a201SDave Airlie 	if (ret) {
7104ae3a201SDave Airlie 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
7114ae3a201SDave Airlie 		return ret;
7124ae3a201SDave Airlie 	}
7139e994444SBen Skeggs 
7149e994444SBen Skeggs 	for (or = 0; or < ARRAY_SIZE(ctrl->sorAssignListWithTag); or++) {
7159e994444SBen Skeggs 		if (ctrl->sorAssignListWithTag[or].displayMask & BIT(outp->index)) {
7169e994444SBen Skeggs 			disp->rm.assigned_sors |= BIT(or);
7179e994444SBen Skeggs 			break;
7189e994444SBen Skeggs 		}
7199e994444SBen Skeggs 	}
7209e994444SBen Skeggs 
7219e994444SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
7229e994444SBen Skeggs 
7239e994444SBen Skeggs 	if (WARN_ON(or == ARRAY_SIZE(ctrl->sorAssignListWithTag)))
7249e994444SBen Skeggs 		return -EINVAL;
7259e994444SBen Skeggs 
7269e994444SBen Skeggs 	ior = nvkm_ior_find(disp, SOR, or);
7279e994444SBen Skeggs 	if (WARN_ON(!ior))
7289e994444SBen Skeggs 		return -EINVAL;
7299e994444SBen Skeggs 
7309e994444SBen Skeggs 	nvkm_outp_acquire_ior(outp, NVKM_OUTP_USER, ior);
7319e994444SBen Skeggs 	return 0;
7329e994444SBen Skeggs }
7339e994444SBen Skeggs 
7349e994444SBen Skeggs static int
r535_disp_get_active(struct nvkm_disp * disp,unsigned head,u32 * displayid)735cf6b2b5eSBen Skeggs r535_disp_get_active(struct nvkm_disp *disp, unsigned head, u32 *displayid)
7369e994444SBen Skeggs {
7379e994444SBen Skeggs 	NV0073_CTRL_SYSTEM_GET_ACTIVE_PARAMS *ctrl;
7384ae3a201SDave Airlie 	int ret;
7399e994444SBen Skeggs 
7409e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
7419e994444SBen Skeggs 				    NV0073_CTRL_CMD_SYSTEM_GET_ACTIVE, sizeof(*ctrl));
7429e994444SBen Skeggs 	if (IS_ERR(ctrl))
7439e994444SBen Skeggs 		return PTR_ERR(ctrl);
7449e994444SBen Skeggs 
7459e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
7469e994444SBen Skeggs 	ctrl->head = head;
7479e994444SBen Skeggs 
7484ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
7494ae3a201SDave Airlie 	if (ret) {
7504ae3a201SDave Airlie 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
7514ae3a201SDave Airlie 		return ret;
7524ae3a201SDave Airlie 	}
7539e994444SBen Skeggs 
7549e994444SBen Skeggs 	*displayid = ctrl->displayId;
7559e994444SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
7569e994444SBen Skeggs 	return 0;
7579e994444SBen Skeggs }
7589e994444SBen Skeggs 
7599e994444SBen Skeggs static struct nvkm_ior *
r535_outp_inherit(struct nvkm_outp * outp)7609e994444SBen Skeggs r535_outp_inherit(struct nvkm_outp *outp)
7619e994444SBen Skeggs {
7629e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
7639e994444SBen Skeggs 	struct nvkm_head *head;
7649e994444SBen Skeggs 	u32 displayid;
7659e994444SBen Skeggs 	int ret;
7669e994444SBen Skeggs 
7679e994444SBen Skeggs 	list_for_each_entry(head, &disp->heads, head) {
768cf6b2b5eSBen Skeggs 		const struct nvkm_rm_api *rmapi = disp->rm.objcom.client->gsp->rm->api;
769cf6b2b5eSBen Skeggs 
770cf6b2b5eSBen Skeggs 		ret = rmapi->disp->get_active(disp, head->id, &displayid);
7719e994444SBen Skeggs 		if (WARN_ON(ret))
7729e994444SBen Skeggs 			return NULL;
7739e994444SBen Skeggs 
7749e994444SBen Skeggs 		if (displayid == BIT(outp->index)) {
7759e994444SBen Skeggs 			NV0073_CTRL_SPECIFIC_OR_GET_INFO_PARAMS *ctrl;
7769e994444SBen Skeggs 			u32 id, proto;
7779e994444SBen Skeggs 			struct nvkm_ior *ior;
7789e994444SBen Skeggs 
7799e994444SBen Skeggs 			ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
7809e994444SBen Skeggs 						    NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO,
7819e994444SBen Skeggs 						    sizeof(*ctrl));
7829e994444SBen Skeggs 			if (IS_ERR(ctrl))
7839e994444SBen Skeggs 				return NULL;
7849e994444SBen Skeggs 
7859e994444SBen Skeggs 			ctrl->subDeviceInstance = 0;
7869e994444SBen Skeggs 			ctrl->displayId = displayid;
7879e994444SBen Skeggs 
7884ae3a201SDave Airlie 			ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
7894ae3a201SDave Airlie 			if (ret) {
7904ae3a201SDave Airlie 				nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
7919e994444SBen Skeggs 				return NULL;
7924ae3a201SDave Airlie 			}
7939e994444SBen Skeggs 
7949e994444SBen Skeggs 			id = ctrl->index;
7959e994444SBen Skeggs 			proto = ctrl->protocol;
7969e994444SBen Skeggs 			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
7979e994444SBen Skeggs 
7989e994444SBen Skeggs 			ior = nvkm_ior_find(disp, SOR, id);
7999e994444SBen Skeggs 			if (WARN_ON(!ior))
8009e994444SBen Skeggs 				return NULL;
8019e994444SBen Skeggs 
8029e994444SBen Skeggs 			switch (proto) {
8039e994444SBen Skeggs 			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_A:
8049e994444SBen Skeggs 				ior->arm.proto = TMDS;
8059e994444SBen Skeggs 				ior->arm.link = 1;
8069e994444SBen Skeggs 				break;
8079e994444SBen Skeggs 			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_B:
8089e994444SBen Skeggs 				ior->arm.proto = TMDS;
8099e994444SBen Skeggs 				ior->arm.link = 2;
8109e994444SBen Skeggs 				break;
8119e994444SBen Skeggs 			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DUAL_TMDS:
8129e994444SBen Skeggs 				ior->arm.proto = TMDS;
8139e994444SBen Skeggs 				ior->arm.link = 3;
8149e994444SBen Skeggs 				break;
8159e994444SBen Skeggs 			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A:
8169e994444SBen Skeggs 				ior->arm.proto = DP;
8179e994444SBen Skeggs 				ior->arm.link = 1;
8189e994444SBen Skeggs 				break;
8199e994444SBen Skeggs 			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B:
8209e994444SBen Skeggs 				ior->arm.proto = DP;
8219e994444SBen Skeggs 				ior->arm.link = 2;
8229e994444SBen Skeggs 				break;
8239e994444SBen Skeggs 			default:
8249e994444SBen Skeggs 				WARN_ON(1);
8259e994444SBen Skeggs 				return NULL;
8269e994444SBen Skeggs 			}
8279e994444SBen Skeggs 
8289e994444SBen Skeggs 			ior->arm.proto_evo = proto;
8299e994444SBen Skeggs 			ior->arm.head = BIT(head->id);
8309e994444SBen Skeggs 			disp->rm.assigned_sors |= BIT(ior->id);
8319e994444SBen Skeggs 			return ior;
8329e994444SBen Skeggs 		}
8339e994444SBen Skeggs 	}
8349e994444SBen Skeggs 
8359e994444SBen Skeggs 	return NULL;
8369e994444SBen Skeggs }
8379e994444SBen Skeggs 
8389e994444SBen Skeggs static int
r535_outp_dfp_get_info(struct nvkm_outp * outp)8399e994444SBen Skeggs r535_outp_dfp_get_info(struct nvkm_outp *outp)
8409e994444SBen Skeggs {
8419e994444SBen Skeggs 	NV0073_CTRL_DFP_GET_INFO_PARAMS *ctrl;
8429e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
8434ae3a201SDave Airlie 	int ret;
8449e994444SBen Skeggs 
8459e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DFP_GET_INFO, sizeof(*ctrl));
8469e994444SBen Skeggs 	if (IS_ERR(ctrl))
8479e994444SBen Skeggs 		return PTR_ERR(ctrl);
8489e994444SBen Skeggs 
8499e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
8509e994444SBen Skeggs 
8514ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
8524ae3a201SDave Airlie 	if (ret) {
8534ae3a201SDave Airlie 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
8544ae3a201SDave Airlie 		return ret;
8554ae3a201SDave Airlie 	}
8569e994444SBen Skeggs 
8579e994444SBen Skeggs 	nvkm_debug(&disp->engine.subdev, "DFP %08x: flags:%08x flags2:%08x\n",
8589e994444SBen Skeggs 		   ctrl->displayId, ctrl->flags, ctrl->flags2);
8599e994444SBen Skeggs 
8609e994444SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
8619e994444SBen Skeggs 	return 0;
8629e994444SBen Skeggs }
8639e994444SBen Skeggs 
8649e994444SBen Skeggs static int
r535_disp_get_connect_state(struct nvkm_disp * disp,unsigned display_id)865bfbae411SBen Skeggs r535_disp_get_connect_state(struct nvkm_disp *disp, unsigned display_id)
8669e994444SBen Skeggs {
8679e994444SBen Skeggs 	NV0073_CTRL_SYSTEM_GET_CONNECT_STATE_PARAMS *ctrl;
8689e994444SBen Skeggs 	int ret;
8699e994444SBen Skeggs 
8709e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
8719e994444SBen Skeggs 				    NV0073_CTRL_CMD_SYSTEM_GET_CONNECT_STATE, sizeof(*ctrl));
8729e994444SBen Skeggs 	if (IS_ERR(ctrl))
8739e994444SBen Skeggs 		return PTR_ERR(ctrl);
8749e994444SBen Skeggs 
8759e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
876bfbae411SBen Skeggs 	ctrl->displayMask = BIT(display_id);
8779e994444SBen Skeggs 
8784ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
879bfbae411SBen Skeggs 	if (ret == 0 && (ctrl->displayMask & BIT(display_id)))
880bfbae411SBen Skeggs 		ret = 1;
881bfbae411SBen Skeggs 
8824ae3a201SDave Airlie 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
8834ae3a201SDave Airlie 	return ret;
8844ae3a201SDave Airlie }
8859e994444SBen Skeggs 
886bfbae411SBen Skeggs static int
r535_outp_detect(struct nvkm_outp * outp)887bfbae411SBen Skeggs r535_outp_detect(struct nvkm_outp *outp)
888bfbae411SBen Skeggs {
889bfbae411SBen Skeggs 	const struct nvkm_rm_api *rmapi = outp->disp->rm.objcom.client->gsp->rm->api;
890bfbae411SBen Skeggs 	int ret;
891bfbae411SBen Skeggs 
892bfbae411SBen Skeggs 	ret = rmapi->disp->get_connect_state(outp->disp, outp->index);
893bfbae411SBen Skeggs 	if (ret == 1) {
8949e994444SBen Skeggs 		ret = r535_outp_dfp_get_info(outp);
8959e994444SBen Skeggs 		if (ret == 0)
8969e994444SBen Skeggs 			ret = 1;
8979e994444SBen Skeggs 	}
8989e994444SBen Skeggs 
8999e994444SBen Skeggs 	return ret;
9009e994444SBen Skeggs }
9019e994444SBen Skeggs 
9029e994444SBen Skeggs static int
r535_dp_mst_id_put(struct nvkm_outp * outp,u32 id)9039e994444SBen Skeggs r535_dp_mst_id_put(struct nvkm_outp *outp, u32 id)
9049e994444SBen Skeggs {
9059e994444SBen Skeggs 	NV0073_CTRL_CMD_DP_TOPOLOGY_FREE_DISPLAYID_PARAMS *ctrl;
9069e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
9079e994444SBen Skeggs 
9089e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
9099e994444SBen Skeggs 				    NV0073_CTRL_CMD_DP_TOPOLOGY_FREE_DISPLAYID, sizeof(*ctrl));
9109e994444SBen Skeggs 	if (IS_ERR(ctrl))
9119e994444SBen Skeggs 		return PTR_ERR(ctrl);
9129e994444SBen Skeggs 
9139e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
9149e994444SBen Skeggs 	ctrl->displayId = id;
9159e994444SBen Skeggs 	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
9169e994444SBen Skeggs }
9179e994444SBen Skeggs 
9189e994444SBen Skeggs static int
r535_dp_mst_id_get(struct nvkm_outp * outp,u32 * pid)9199e994444SBen Skeggs r535_dp_mst_id_get(struct nvkm_outp *outp, u32 *pid)
9209e994444SBen Skeggs {
9219e994444SBen Skeggs 	NV0073_CTRL_CMD_DP_TOPOLOGY_ALLOCATE_DISPLAYID_PARAMS *ctrl;
9229e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
9234ae3a201SDave Airlie 	int ret;
9249e994444SBen Skeggs 
9259e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
9269e994444SBen Skeggs 				    NV0073_CTRL_CMD_DP_TOPOLOGY_ALLOCATE_DISPLAYID,
9279e994444SBen Skeggs 				    sizeof(*ctrl));
9289e994444SBen Skeggs 	if (IS_ERR(ctrl))
9299e994444SBen Skeggs 		return PTR_ERR(ctrl);
9309e994444SBen Skeggs 
9319e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
9329e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
9334ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
9344ae3a201SDave Airlie 	if (ret) {
9354ae3a201SDave Airlie 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
9364ae3a201SDave Airlie 		return ret;
9374ae3a201SDave Airlie 	}
9389e994444SBen Skeggs 
9399e994444SBen Skeggs 	*pid = ctrl->displayIdAssigned;
9409e994444SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
9419e994444SBen Skeggs 	return 0;
9429e994444SBen Skeggs }
9439e994444SBen Skeggs 
9449e994444SBen Skeggs static int
r535_dp_drive(struct nvkm_outp * outp,u8 lanes,u8 pe[4],u8 vs[4])9459e994444SBen Skeggs r535_dp_drive(struct nvkm_outp *outp, u8 lanes, u8 pe[4], u8 vs[4])
9469e994444SBen Skeggs {
9479e994444SBen Skeggs 	NV0073_CTRL_DP_LANE_DATA_PARAMS *ctrl;
9489e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
9499e994444SBen Skeggs 
9509e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
9519e994444SBen Skeggs 				    NV0073_CTRL_CMD_DP_SET_LANE_DATA, sizeof(*ctrl));
9529e994444SBen Skeggs 	if (IS_ERR(ctrl))
9539e994444SBen Skeggs 		return PTR_ERR(ctrl);
9549e994444SBen Skeggs 
9559e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
9569e994444SBen Skeggs 	ctrl->numLanes = lanes;
9579e994444SBen Skeggs 	for (int i = 0; i < lanes; i++)
9589e994444SBen Skeggs 		ctrl->data[i] = NVVAL(NV0073_CTRL, DP_LANE_DATA,  PREEMPHASIS, pe[i]) |
9599e994444SBen Skeggs 				NVVAL(NV0073_CTRL, DP_LANE_DATA, DRIVECURRENT, vs[i]);
9609e994444SBen Skeggs 
9619e994444SBen Skeggs 	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
9629e994444SBen Skeggs }
9639e994444SBen Skeggs 
9649e994444SBen Skeggs static int
r535_dp_train_target(struct nvkm_outp * outp,u8 target,bool mst,u8 link_nr,u8 link_bw)9659e994444SBen Skeggs r535_dp_train_target(struct nvkm_outp *outp, u8 target, bool mst, u8 link_nr, u8 link_bw)
9669e994444SBen Skeggs {
9679e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
9689e994444SBen Skeggs 	NV0073_CTRL_DP_CTRL_PARAMS *ctrl;
969eb284f4bSLyude Paul 	int ret, retries;
970eb284f4bSLyude Paul 	u32 cmd, data;
9719e994444SBen Skeggs 
972eb284f4bSLyude Paul 	cmd = NVDEF(NV0073_CTRL, DP_CMD, SET_LANE_COUNT, TRUE) |
973eb284f4bSLyude Paul 	      NVDEF(NV0073_CTRL, DP_CMD, SET_LINK_BW, TRUE) |
974eb284f4bSLyude Paul 	      NVDEF(NV0073_CTRL, DP_CMD, TRAIN_PHY_REPEATER, YES);
975eb284f4bSLyude Paul 	data = NVVAL(NV0073_CTRL, DP_DATA, SET_LANE_COUNT, link_nr) |
976eb284f4bSLyude Paul 	       NVVAL(NV0073_CTRL, DP_DATA, SET_LINK_BW, link_bw) |
977eb284f4bSLyude Paul 	       NVVAL(NV0073_CTRL, DP_DATA, TARGET, target);
978eb284f4bSLyude Paul 
979eb284f4bSLyude Paul 	if (mst)
980eb284f4bSLyude Paul 		cmd |= NVDEF(NV0073_CTRL, DP_CMD, SET_FORMAT_MODE, MULTI_STREAM);
981eb284f4bSLyude Paul 
982eb284f4bSLyude Paul 	if (outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
983eb284f4bSLyude Paul 		cmd |= NVDEF(NV0073_CTRL, DP_CMD, SET_ENHANCED_FRAMING, TRUE);
984eb284f4bSLyude Paul 
985eb284f4bSLyude Paul 	if (target == 0 &&
986eb284f4bSLyude Paul 	     (outp->dp.dpcd[DPCD_RC02] & 0x20) &&
987eb284f4bSLyude Paul 	    !(outp->dp.dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED))
988eb284f4bSLyude Paul 		cmd |= NVDEF(NV0073_CTRL, DP_CMD, POST_LT_ADJ_REQ_GRANTED, YES);
989eb284f4bSLyude Paul 
990eb284f4bSLyude Paul 	/* We should retry up to 3 times, but only if GSP asks politely */
991eb284f4bSLyude Paul 	for (retries = 0; retries < 3; ++retries) {
992eb284f4bSLyude Paul 		ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DP_CTRL,
993eb284f4bSLyude Paul 					    sizeof(*ctrl));
9949e994444SBen Skeggs 		if (IS_ERR(ctrl))
9959e994444SBen Skeggs 			return PTR_ERR(ctrl);
9969e994444SBen Skeggs 
9979e994444SBen Skeggs 		ctrl->subDeviceInstance = 0;
9989e994444SBen Skeggs 		ctrl->displayId = BIT(outp->index);
999eb284f4bSLyude Paul 		ctrl->retryTimeMs = 0;
1000eb284f4bSLyude Paul 		ctrl->cmd = cmd;
1001eb284f4bSLyude Paul 		ctrl->data = data;
10029e994444SBen Skeggs 
10034ae3a201SDave Airlie 		ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
1004b6ad7debSDave Airlie 		if ((ret == -EAGAIN || ret == -EBUSY) && ctrl->retryTimeMs) {
1005eb284f4bSLyude Paul 			/*
1006eb284f4bSLyude Paul 			 * Device (likely an eDP panel) isn't ready yet, wait for the time specified
1007eb284f4bSLyude Paul 			 * by GSP before retrying again
1008eb284f4bSLyude Paul 			 */
1009eb284f4bSLyude Paul 			nvkm_debug(&disp->engine.subdev,
1010eb284f4bSLyude Paul 				   "Waiting %dms for GSP LT panel delay before retrying\n",
1011eb284f4bSLyude Paul 				   ctrl->retryTimeMs);
1012eb284f4bSLyude Paul 			msleep(ctrl->retryTimeMs);
10134ae3a201SDave Airlie 			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
1014eb284f4bSLyude Paul 		} else {
1015eb284f4bSLyude Paul 			/* GSP didn't say to retry, or we were successful */
1016eb284f4bSLyude Paul 			if (ctrl->err)
1017eb284f4bSLyude Paul 				ret = -EIO;
1018eb284f4bSLyude Paul 			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
1019eb284f4bSLyude Paul 			break;
1020eb284f4bSLyude Paul 		}
10214ae3a201SDave Airlie 	}
10229e994444SBen Skeggs 
10239e994444SBen Skeggs 	return ret;
10249e994444SBen Skeggs }
10259e994444SBen Skeggs 
10269e994444SBen Skeggs static int
r535_dp_train(struct nvkm_outp * outp,bool retrain)10279e994444SBen Skeggs r535_dp_train(struct nvkm_outp *outp, bool retrain)
10289e994444SBen Skeggs {
10299e994444SBen Skeggs 	for (int target = outp->dp.lttprs; target >= 0; target--) {
10309e994444SBen Skeggs 		int ret = r535_dp_train_target(outp, target, outp->dp.lt.mst,
10319e994444SBen Skeggs 							     outp->dp.lt.nr,
10329e994444SBen Skeggs 							     outp->dp.lt.bw);
10339e994444SBen Skeggs 		if (ret)
10349e994444SBen Skeggs 			return ret;
10359e994444SBen Skeggs 	}
10369e994444SBen Skeggs 
10379e994444SBen Skeggs 	return 0;
10389e994444SBen Skeggs }
10399e994444SBen Skeggs 
10409e994444SBen Skeggs static int
r535_dp_set_indexed_link_rates(struct nvkm_outp * outp)1041a3f32329SBen Skeggs r535_dp_set_indexed_link_rates(struct nvkm_outp *outp)
10429e994444SBen Skeggs {
10439e994444SBen Skeggs 	NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES_PARAMS *ctrl;
10449e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
10459e994444SBen Skeggs 
10469e994444SBen Skeggs 	if (WARN_ON(outp->dp.rates > ARRAY_SIZE(ctrl->linkRateTbl)))
10479e994444SBen Skeggs 		return -EINVAL;
10489e994444SBen Skeggs 
10499e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
10509e994444SBen Skeggs 				    NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES, sizeof(*ctrl));
10519e994444SBen Skeggs 	if (IS_ERR(ctrl))
10529e994444SBen Skeggs 		return PTR_ERR(ctrl);
10539e994444SBen Skeggs 
10549e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
10559e994444SBen Skeggs 	for (int i = 0; i < outp->dp.rates; i++)
10569e994444SBen Skeggs 		ctrl->linkRateTbl[outp->dp.rate[i].dpcd] = outp->dp.rate[i].rate * 10 / 200;
10579e994444SBen Skeggs 
10589e994444SBen Skeggs 	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
10599e994444SBen Skeggs }
10609e994444SBen Skeggs 
10619e994444SBen Skeggs static int
r535_dp_rates(struct nvkm_outp * outp)1062a3f32329SBen Skeggs r535_dp_rates(struct nvkm_outp *outp)
1063a3f32329SBen Skeggs {
1064a3f32329SBen Skeggs 	struct nvkm_rm *rm = outp->disp->rm.objcom.client->gsp->rm;
1065a3f32329SBen Skeggs 
1066a3f32329SBen Skeggs 	if (outp->conn->info.type != DCB_CONNECTOR_eDP ||
1067a3f32329SBen Skeggs 	    !outp->dp.rates || outp->dp.rate[0].dpcd < 0)
1068a3f32329SBen Skeggs 		return 0;
1069a3f32329SBen Skeggs 
1070a3f32329SBen Skeggs 	return rm->api->disp->dp.set_indexed_link_rates(outp);
1071a3f32329SBen Skeggs }
1072a3f32329SBen Skeggs 
1073a3f32329SBen Skeggs static int
r535_dp_aux_xfer(struct nvkm_outp * outp,u8 type,u32 addr,u8 * data,u8 * psize)10749e994444SBen Skeggs r535_dp_aux_xfer(struct nvkm_outp *outp, u8 type, u32 addr, u8 *data, u8 *psize)
10759e994444SBen Skeggs {
10769e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
10779e994444SBen Skeggs 	NV0073_CTRL_DP_AUXCH_CTRL_PARAMS *ctrl;
10789e994444SBen Skeggs 	u8 size = *psize;
10799e994444SBen Skeggs 	int ret;
10809776c0a7SDave Airlie 	int retries;
10819e994444SBen Skeggs 
10829776c0a7SDave Airlie 	for (retries = 0; retries < 3; ++retries) {
10839e994444SBen Skeggs 		ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DP_AUXCH_CTRL, sizeof(*ctrl));
10849e994444SBen Skeggs 		if (IS_ERR(ctrl))
10859e994444SBen Skeggs 			return PTR_ERR(ctrl);
10869e994444SBen Skeggs 
10879e994444SBen Skeggs 		ctrl->subDeviceInstance = 0;
10889e994444SBen Skeggs 		ctrl->displayId = BIT(outp->index);
10899e994444SBen Skeggs 		ctrl->bAddrOnly = !size;
10909e994444SBen Skeggs 		ctrl->cmd = type;
10919e994444SBen Skeggs 		if (ctrl->bAddrOnly) {
10929e994444SBen Skeggs 			ctrl->cmd = NVDEF_SET(ctrl->cmd, NV0073_CTRL, DP_AUXCH_CMD, REQ_TYPE, WRITE);
10939e994444SBen Skeggs 			ctrl->cmd = NVDEF_SET(ctrl->cmd, NV0073_CTRL, DP_AUXCH_CMD,  I2C_MOT, FALSE);
10949e994444SBen Skeggs 		}
10959e994444SBen Skeggs 		ctrl->addr = addr;
10969e994444SBen Skeggs 		ctrl->size = !ctrl->bAddrOnly ? (size - 1) : 0;
10979e994444SBen Skeggs 		memcpy(ctrl->data, data, size);
10989e994444SBen Skeggs 
10994ae3a201SDave Airlie 		ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
11009776c0a7SDave Airlie 		if ((ret == -EAGAIN || ret == -EBUSY) && ctrl->retryTimeMs) {
11019776c0a7SDave Airlie 			/*
11029776c0a7SDave Airlie 			 * Device (likely an eDP panel) isn't ready yet, wait for the time specified
11039776c0a7SDave Airlie 			 * by GSP before retrying again
11049776c0a7SDave Airlie 			 */
11059776c0a7SDave Airlie 			nvkm_debug(&disp->engine.subdev,
11069776c0a7SDave Airlie 				   "Waiting %dms for GSP LT panel delay before retrying in AUX\n",
11079776c0a7SDave Airlie 				   ctrl->retryTimeMs);
11089776c0a7SDave Airlie 			msleep(ctrl->retryTimeMs);
11094ae3a201SDave Airlie 			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
11109776c0a7SDave Airlie 		} else {
11119e994444SBen Skeggs 			memcpy(data, ctrl->data, size);
11129e994444SBen Skeggs 			*psize = ctrl->size;
11139e994444SBen Skeggs 			ret = ctrl->replyType;
11149e994444SBen Skeggs 			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
11159776c0a7SDave Airlie 			break;
11169776c0a7SDave Airlie 		}
11179776c0a7SDave Airlie 	}
11189e994444SBen Skeggs 	return ret;
11199e994444SBen Skeggs }
11209e994444SBen Skeggs 
11219e994444SBen Skeggs static int
r535_dp_aux_pwr(struct nvkm_outp * outp,bool pu)11229e994444SBen Skeggs r535_dp_aux_pwr(struct nvkm_outp *outp, bool pu)
11239e994444SBen Skeggs {
11249e994444SBen Skeggs 	return 0;
11259e994444SBen Skeggs }
11269e994444SBen Skeggs 
11279e994444SBen Skeggs static void
r535_dp_release(struct nvkm_outp * outp)11289e994444SBen Skeggs r535_dp_release(struct nvkm_outp *outp)
11299e994444SBen Skeggs {
11309e994444SBen Skeggs 	if (!outp->dp.lt.bw) {
11319e994444SBen Skeggs 		if (!WARN_ON(!outp->dp.rates))
11329e994444SBen Skeggs 			outp->dp.lt.bw = outp->dp.rate[0].rate / 27000;
11339e994444SBen Skeggs 		else
11349e994444SBen Skeggs 			outp->dp.lt.bw = 0x06;
11359e994444SBen Skeggs 	}
11369e994444SBen Skeggs 
11379e994444SBen Skeggs 	outp->dp.lt.nr = 0;
11389e994444SBen Skeggs 
11399e994444SBen Skeggs 	r535_dp_train_target(outp, 0, outp->dp.lt.mst, outp->dp.lt.nr, outp->dp.lt.bw);
11409e994444SBen Skeggs 	r535_outp_release(outp);
11419e994444SBen Skeggs }
11429e994444SBen Skeggs 
11439e994444SBen Skeggs static int
r535_dp_acquire(struct nvkm_outp * outp,bool hda)11449e994444SBen Skeggs r535_dp_acquire(struct nvkm_outp *outp, bool hda)
11459e994444SBen Skeggs {
11469e994444SBen Skeggs 	int ret;
11479e994444SBen Skeggs 
11489e994444SBen Skeggs 	ret = r535_outp_acquire(outp, hda);
11499e994444SBen Skeggs 	if (ret)
11509e994444SBen Skeggs 		return ret;
11519e994444SBen Skeggs 
11529e994444SBen Skeggs 	return 0;
11539e994444SBen Skeggs }
11549e994444SBen Skeggs 
11559e994444SBen Skeggs static const struct nvkm_outp_func
11569e994444SBen Skeggs r535_dp = {
11579e994444SBen Skeggs 	.detect = r535_outp_detect,
11589e994444SBen Skeggs 	.inherit = r535_outp_inherit,
11599e994444SBen Skeggs 	.acquire = r535_dp_acquire,
11609e994444SBen Skeggs 	.release = r535_dp_release,
11619e994444SBen Skeggs 	.dp.aux_pwr = r535_dp_aux_pwr,
11629e994444SBen Skeggs 	.dp.aux_xfer = r535_dp_aux_xfer,
11639e994444SBen Skeggs 	.dp.mst_id_get = r535_dp_mst_id_get,
11649e994444SBen Skeggs 	.dp.mst_id_put = r535_dp_mst_id_put,
11659e994444SBen Skeggs 	.dp.rates = r535_dp_rates,
11669e994444SBen Skeggs 	.dp.train = r535_dp_train,
11679e994444SBen Skeggs 	.dp.drive = r535_dp_drive,
11689e994444SBen Skeggs };
11699e994444SBen Skeggs 
11709e994444SBen Skeggs static int
r535_dp_get_caps(struct nvkm_disp * disp,int * plink_bw,bool * pmst,bool * pwm)117137a82fa3SBen Skeggs r535_dp_get_caps(struct nvkm_disp *disp, int *plink_bw, bool *pmst, bool *pwm)
117237a82fa3SBen Skeggs {
117337a82fa3SBen Skeggs 	NV0073_CTRL_CMD_DP_GET_CAPS_PARAMS *ctrl;
117437a82fa3SBen Skeggs 	int ret;
117537a82fa3SBen Skeggs 
117637a82fa3SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
117737a82fa3SBen Skeggs 				    NV0073_CTRL_CMD_DP_GET_CAPS, sizeof(*ctrl));
117837a82fa3SBen Skeggs 	if (IS_ERR(ctrl))
117937a82fa3SBen Skeggs 		return PTR_ERR(ctrl);
118037a82fa3SBen Skeggs 
118137a82fa3SBen Skeggs 	ctrl->sorIndex = ~0;
118237a82fa3SBen Skeggs 
118337a82fa3SBen Skeggs 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
118437a82fa3SBen Skeggs 	if (ret) {
118537a82fa3SBen Skeggs 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
118637a82fa3SBen Skeggs 		return ret;
118737a82fa3SBen Skeggs 	}
118837a82fa3SBen Skeggs 
118937a82fa3SBen Skeggs 	switch (NVVAL_GET(ctrl->maxLinkRate, NV0073_CTRL_CMD, DP_GET_CAPS, MAX_LINK_RATE)) {
119037a82fa3SBen Skeggs 	case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_1_62:
119137a82fa3SBen Skeggs 		*plink_bw = 0x06;
119237a82fa3SBen Skeggs 		break;
119337a82fa3SBen Skeggs 	case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_2_70:
119437a82fa3SBen Skeggs 		*plink_bw = 0x0a;
119537a82fa3SBen Skeggs 		break;
119637a82fa3SBen Skeggs 	case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_5_40:
119737a82fa3SBen Skeggs 		*plink_bw = 0x14;
119837a82fa3SBen Skeggs 		break;
119937a82fa3SBen Skeggs 	case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_8_10:
120037a82fa3SBen Skeggs 		*plink_bw = 0x1e;
120137a82fa3SBen Skeggs 		break;
120237a82fa3SBen Skeggs 	default:
120337a82fa3SBen Skeggs 		*plink_bw = 0x00;
120437a82fa3SBen Skeggs 		break;
120537a82fa3SBen Skeggs 	}
120637a82fa3SBen Skeggs 
120737a82fa3SBen Skeggs 	*pmst = ctrl->bIsMultistreamSupported;
120837a82fa3SBen Skeggs 	*pwm = ctrl->bHasIncreasedWatermarkLimits;
120937a82fa3SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
121037a82fa3SBen Skeggs 	return 0;
121137a82fa3SBen Skeggs }
121237a82fa3SBen Skeggs 
121337a82fa3SBen Skeggs static int
r535_tmds_edid_get(struct nvkm_outp * outp,u8 * data,u16 * psize)12149e994444SBen Skeggs r535_tmds_edid_get(struct nvkm_outp *outp, u8 *data, u16 *psize)
12159e994444SBen Skeggs {
12169e994444SBen Skeggs 	NV0073_CTRL_SPECIFIC_GET_EDID_V2_PARAMS *ctrl;
12179e994444SBen Skeggs 	struct nvkm_disp *disp = outp->disp;
12189e994444SBen Skeggs 	int ret = -E2BIG;
12199e994444SBen Skeggs 
12209e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
12219e994444SBen Skeggs 				    NV0073_CTRL_CMD_SPECIFIC_GET_EDID_V2, sizeof(*ctrl));
12229e994444SBen Skeggs 	if (IS_ERR(ctrl))
12239e994444SBen Skeggs 		return PTR_ERR(ctrl);
12249e994444SBen Skeggs 
12259e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
12269e994444SBen Skeggs 	ctrl->displayId = BIT(outp->index);
12279e994444SBen Skeggs 
12284ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
12294ae3a201SDave Airlie 	if (ret) {
12304ae3a201SDave Airlie 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
12314ae3a201SDave Airlie 		return ret;
12324ae3a201SDave Airlie 	}
12339e994444SBen Skeggs 
12344ae3a201SDave Airlie 	ret = -E2BIG;
12359e994444SBen Skeggs 	if (ctrl->bufferSize <= *psize) {
12369e994444SBen Skeggs 		memcpy(data, ctrl->edidBuffer, ctrl->bufferSize);
12379e994444SBen Skeggs 		*psize = ctrl->bufferSize;
12389e994444SBen Skeggs 		ret = 0;
12399e994444SBen Skeggs 	}
12409e994444SBen Skeggs 
12419e994444SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
12429e994444SBen Skeggs 	return ret;
12439e994444SBen Skeggs }
12449e994444SBen Skeggs 
12459e994444SBen Skeggs static const struct nvkm_outp_func
12469e994444SBen Skeggs r535_tmds = {
12479e994444SBen Skeggs 	.detect = r535_outp_detect,
12489e994444SBen Skeggs 	.inherit = r535_outp_inherit,
12499e994444SBen Skeggs 	.acquire = r535_outp_acquire,
12509e994444SBen Skeggs 	.release = r535_outp_release,
12519e994444SBen Skeggs 	.edid_get = r535_tmds_edid_get,
12529e994444SBen Skeggs };
12539e994444SBen Skeggs 
12549e994444SBen Skeggs static int
r535_outp_new(struct nvkm_disp * disp,u32 id)12559e994444SBen Skeggs r535_outp_new(struct nvkm_disp *disp, u32 id)
12569e994444SBen Skeggs {
125737a82fa3SBen Skeggs 	const struct nvkm_rm_api *rmapi = disp->rm.objcom.client->gsp->rm->api;
12589e994444SBen Skeggs 	NV0073_CTRL_SPECIFIC_OR_GET_INFO_PARAMS *ctrl;
12599e994444SBen Skeggs 	enum nvkm_ior_proto proto;
12609e994444SBen Skeggs 	struct dcb_output dcbE = {};
12619e994444SBen Skeggs 	struct nvkm_conn *conn;
12629e994444SBen Skeggs 	struct nvkm_outp *outp;
12639e994444SBen Skeggs 	u8 locn, link = 0;
12649e994444SBen Skeggs 	int ret;
12659e994444SBen Skeggs 
12669e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
12679e994444SBen Skeggs 				    NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO, sizeof(*ctrl));
12689e994444SBen Skeggs 	if (IS_ERR(ctrl))
12699e994444SBen Skeggs 		return PTR_ERR(ctrl);
12709e994444SBen Skeggs 
12719e994444SBen Skeggs 	ctrl->subDeviceInstance = 0;
12729e994444SBen Skeggs 	ctrl->displayId = BIT(id);
12739e994444SBen Skeggs 
12744ae3a201SDave Airlie 	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));
12754ae3a201SDave Airlie 	if (ret) {
12764ae3a201SDave Airlie 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
12774ae3a201SDave Airlie 		return ret;
12784ae3a201SDave Airlie 	}
12799e994444SBen Skeggs 
12809e994444SBen Skeggs 	switch (ctrl->type) {
12819e994444SBen Skeggs 	case NV0073_CTRL_SPECIFIC_OR_TYPE_NONE:
12829e994444SBen Skeggs 		return 0;
12839e994444SBen Skeggs 	case NV0073_CTRL_SPECIFIC_OR_TYPE_SOR:
12849e994444SBen Skeggs 		switch (ctrl->protocol) {
12859e994444SBen Skeggs 		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_A:
12869e994444SBen Skeggs 			proto = TMDS;
12879e994444SBen Skeggs 			link = 1;
12889e994444SBen Skeggs 			break;
12899e994444SBen Skeggs 		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_B:
12909e994444SBen Skeggs 			proto = TMDS;
12919e994444SBen Skeggs 			link = 2;
12929e994444SBen Skeggs 			break;
12939e994444SBen Skeggs 		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DUAL_TMDS:
12949e994444SBen Skeggs 			proto = TMDS;
12959e994444SBen Skeggs 			link = 3;
12969e994444SBen Skeggs 			break;
12979e994444SBen Skeggs 		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A:
12989e994444SBen Skeggs 			proto = DP;
12999e994444SBen Skeggs 			link = 1;
13009e994444SBen Skeggs 			break;
13019e994444SBen Skeggs 		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B:
13029e994444SBen Skeggs 			proto = DP;
13039e994444SBen Skeggs 			link = 2;
13049e994444SBen Skeggs 			break;
13059e994444SBen Skeggs 		default:
13069e994444SBen Skeggs 			WARN_ON(1);
13079e994444SBen Skeggs 			return -EINVAL;
13089e994444SBen Skeggs 		}
13099e994444SBen Skeggs 
13109e994444SBen Skeggs 		break;
13119e994444SBen Skeggs 	default:
13129e994444SBen Skeggs 		WARN_ON(1);
13139e994444SBen Skeggs 		return -EINVAL;
13149e994444SBen Skeggs 	}
13159e994444SBen Skeggs 
13169e994444SBen Skeggs 	locn = ctrl->location;
13179e994444SBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
13189e994444SBen Skeggs 
13199e994444SBen Skeggs 	conn = r535_conn_new(disp, id);
13209e994444SBen Skeggs 	if (IS_ERR(conn))
13219e994444SBen Skeggs 		return PTR_ERR(conn);
13229e994444SBen Skeggs 
13239e994444SBen Skeggs 	switch (proto) {
13249e994444SBen Skeggs 	case TMDS: dcbE.type = DCB_OUTPUT_TMDS; break;
13259e994444SBen Skeggs 	case   DP: dcbE.type = DCB_OUTPUT_DP; break;
13269e994444SBen Skeggs 	default:
13279e994444SBen Skeggs 		WARN_ON(1);
13289e994444SBen Skeggs 		return -EINVAL;
13299e994444SBen Skeggs 	}
13309e994444SBen Skeggs 
13319e994444SBen Skeggs 	dcbE.location = locn;
13329e994444SBen Skeggs 	dcbE.connector = conn->index;
13339e994444SBen Skeggs 	dcbE.heads = disp->head.mask;
13349e994444SBen Skeggs 	dcbE.i2c_index = 0xff;
13359e994444SBen Skeggs 	dcbE.link = dcbE.sorconf.link = link;
13369e994444SBen Skeggs 
13379e994444SBen Skeggs 	if (proto == TMDS) {
13389e994444SBen Skeggs 		ret = nvkm_outp_new_(&r535_tmds, disp, id, &dcbE, &outp);
13399e994444SBen Skeggs 		if (ret)
13409e994444SBen Skeggs 			return ret;
13419e994444SBen Skeggs 	} else {
13429e994444SBen Skeggs 		bool mst, wm;
13439e994444SBen Skeggs 
134437a82fa3SBen Skeggs 		ret = rmapi->disp->dp.get_caps(disp, &dcbE.dpconf.link_bw, &mst, &wm);
134537a82fa3SBen Skeggs 		if (ret)
13464ae3a201SDave Airlie 			return ret;
13479e994444SBen Skeggs 
13489e994444SBen Skeggs 		if (WARN_ON(!dcbE.dpconf.link_bw))
13499e994444SBen Skeggs 			return -EINVAL;
13509e994444SBen Skeggs 
13519e994444SBen Skeggs 		dcbE.dpconf.link_nr = 4;
13529e994444SBen Skeggs 
13539e994444SBen Skeggs 		ret = nvkm_outp_new_(&r535_dp, disp, id, &dcbE, &outp);
13549e994444SBen Skeggs 		if (ret)
13559e994444SBen Skeggs 			return ret;
13569e994444SBen Skeggs 
13579e994444SBen Skeggs 		outp->dp.mst = mst;
13589e994444SBen Skeggs 		outp->dp.increased_wm = wm;
13599e994444SBen Skeggs 	}
13609e994444SBen Skeggs 
13619e994444SBen Skeggs 
13629e994444SBen Skeggs 	outp->conn = conn;
13639e994444SBen Skeggs 	list_add_tail(&outp->head, &disp->outps);
13649e994444SBen Skeggs 	return 0;
13659e994444SBen Skeggs }
13669e994444SBen Skeggs 
13679e994444SBen Skeggs static void
r535_disp_irq(struct nvkm_gsp_event * event,void * repv,u32 repc)13689e994444SBen Skeggs r535_disp_irq(struct nvkm_gsp_event *event, void *repv, u32 repc)
13699e994444SBen Skeggs {
13709e994444SBen Skeggs 	struct nvkm_disp *disp = container_of(event, typeof(*disp), rm.irq);
13719e994444SBen Skeggs 	Nv2080DpIrqNotification *irq = repv;
13729e994444SBen Skeggs 
13739e994444SBen Skeggs 	if (WARN_ON(repc < sizeof(*irq)))
13749e994444SBen Skeggs 		return;
13759e994444SBen Skeggs 
13769e994444SBen Skeggs 	nvkm_debug(&disp->engine.subdev, "event: dp irq displayId %08x\n", irq->displayId);
13779e994444SBen Skeggs 
13789e994444SBen Skeggs 	if (irq->displayId)
13799e994444SBen Skeggs 		nvkm_event_ntfy(&disp->rm.event, fls(irq->displayId) - 1, NVKM_DPYID_IRQ);
13809e994444SBen Skeggs }
13819e994444SBen Skeggs 
13829e994444SBen Skeggs static void
r535_disp_hpd(struct nvkm_gsp_event * event,void * repv,u32 repc)13839e994444SBen Skeggs r535_disp_hpd(struct nvkm_gsp_event *event, void *repv, u32 repc)
13849e994444SBen Skeggs {
13859e994444SBen Skeggs 	struct nvkm_disp *disp = container_of(event, typeof(*disp), rm.hpd);
13869e994444SBen Skeggs 	Nv2080HotplugNotification *hpd = repv;
13879e994444SBen Skeggs 
13889e994444SBen Skeggs 	if (WARN_ON(repc < sizeof(*hpd)))
13899e994444SBen Skeggs 		return;
13909e994444SBen Skeggs 
13919e994444SBen Skeggs 	nvkm_debug(&disp->engine.subdev, "event: hpd plug %08x unplug %08x\n",
13929e994444SBen Skeggs 		   hpd->plugDisplayMask, hpd->unplugDisplayMask);
13939e994444SBen Skeggs 
13949e994444SBen Skeggs 	for (int i = 0; i < 31; i++) {
13959e994444SBen Skeggs 		u32 mask = 0;
13969e994444SBen Skeggs 
13979e994444SBen Skeggs 		if (hpd->plugDisplayMask & BIT(i))
13989e994444SBen Skeggs 			mask |= NVKM_DPYID_PLUG;
13999e994444SBen Skeggs 		if (hpd->unplugDisplayMask & BIT(i))
14009e994444SBen Skeggs 			mask |= NVKM_DPYID_UNPLUG;
14019e994444SBen Skeggs 
14029e994444SBen Skeggs 		if (mask)
14039e994444SBen Skeggs 			nvkm_event_ntfy(&disp->rm.event, i, mask);
14049e994444SBen Skeggs 	}
14059e994444SBen Skeggs }
14069e994444SBen Skeggs 
14079e994444SBen Skeggs static const struct nvkm_event_func
14089e994444SBen Skeggs r535_disp_event = {
14099e994444SBen Skeggs };
14109e994444SBen Skeggs 
14119e994444SBen Skeggs static void
r535_disp_intr_head_timing(struct nvkm_disp * disp,int head)14129e994444SBen Skeggs r535_disp_intr_head_timing(struct nvkm_disp *disp, int head)
14139e994444SBen Skeggs {
14149e994444SBen Skeggs 	struct nvkm_subdev *subdev = &disp->engine.subdev;
14159e994444SBen Skeggs 	struct nvkm_device *device = subdev->device;
14169e994444SBen Skeggs 	u32 stat = nvkm_rd32(device, 0x611c00 + (head * 0x04));
14179e994444SBen Skeggs 
14189e994444SBen Skeggs 	if (stat & 0x00000002) {
14199e994444SBen Skeggs 		nvkm_disp_vblank(disp, head);
14209e994444SBen Skeggs 
14219e994444SBen Skeggs 		nvkm_wr32(device, 0x611800 + (head * 0x04), 0x00000002);
14229e994444SBen Skeggs 	}
14239e994444SBen Skeggs }
14249e994444SBen Skeggs 
14259e994444SBen Skeggs static irqreturn_t
r535_disp_intr(struct nvkm_inth * inth)14269e994444SBen Skeggs r535_disp_intr(struct nvkm_inth *inth)
14279e994444SBen Skeggs {
14289e994444SBen Skeggs 	struct nvkm_disp *disp = container_of(inth, typeof(*disp), engine.subdev.inth);
14299e994444SBen Skeggs 	struct nvkm_subdev *subdev = &disp->engine.subdev;
14309e994444SBen Skeggs 	struct nvkm_device *device = subdev->device;
14319e994444SBen Skeggs 	unsigned long mask = nvkm_rd32(device, 0x611ec0) & 0x000000ff;
14329e994444SBen Skeggs 	int head;
14339e994444SBen Skeggs 
14349e994444SBen Skeggs 	for_each_set_bit(head, &mask, 8)
14359e994444SBen Skeggs 		r535_disp_intr_head_timing(disp, head);
14369e994444SBen Skeggs 
14379e994444SBen Skeggs 	return IRQ_HANDLED;
14389e994444SBen Skeggs }
14399e994444SBen Skeggs 
14409e994444SBen Skeggs static void
r535_disp_fini(struct nvkm_disp * disp,bool suspend)14419e994444SBen Skeggs r535_disp_fini(struct nvkm_disp *disp, bool suspend)
14429e994444SBen Skeggs {
14439e994444SBen Skeggs 	if (!disp->engine.subdev.use.enabled)
14449e994444SBen Skeggs 		return;
14459e994444SBen Skeggs 
14469e994444SBen Skeggs 	nvkm_gsp_rm_free(&disp->rm.object);
14479e994444SBen Skeggs 
14489e994444SBen Skeggs 	if (!suspend) {
14499e994444SBen Skeggs 		nvkm_gsp_event_dtor(&disp->rm.irq);
14509e994444SBen Skeggs 		nvkm_gsp_event_dtor(&disp->rm.hpd);
14519e994444SBen Skeggs 		nvkm_event_fini(&disp->rm.event);
14529e994444SBen Skeggs 
14539e994444SBen Skeggs 		nvkm_gsp_rm_free(&disp->rm.objcom);
14549e994444SBen Skeggs 		nvkm_gsp_device_dtor(&disp->rm.device);
14559e994444SBen Skeggs 		nvkm_gsp_client_dtor(&disp->rm.client);
14569e994444SBen Skeggs 	}
14579e994444SBen Skeggs }
14589e994444SBen Skeggs 
14599e994444SBen Skeggs static int
r535_disp_init(struct nvkm_disp * disp)14609e994444SBen Skeggs r535_disp_init(struct nvkm_disp *disp)
14619e994444SBen Skeggs {
14629e994444SBen Skeggs 	int ret;
14639e994444SBen Skeggs 
14649e994444SBen Skeggs 	ret = nvkm_gsp_rm_alloc(&disp->rm.device.object, disp->func->root.oclass << 16,
14659e994444SBen Skeggs 				disp->func->root.oclass, 0, &disp->rm.object);
14669e994444SBen Skeggs 	if (ret)
14679e994444SBen Skeggs 		return ret;
14689e994444SBen Skeggs 
14699e994444SBen Skeggs 	return 0;
14709e994444SBen Skeggs }
14719e994444SBen Skeggs 
14729e994444SBen Skeggs static int
r535_disp_get_supported(struct nvkm_disp * disp,unsigned long * pmask)14731cf5940bSBen Skeggs r535_disp_get_supported(struct nvkm_disp *disp, unsigned long *pmask)
14741cf5940bSBen Skeggs {
14751cf5940bSBen Skeggs 	NV0073_CTRL_SYSTEM_GET_SUPPORTED_PARAMS *ctrl;
14761cf5940bSBen Skeggs 
14771cf5940bSBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,
14781cf5940bSBen Skeggs 				   NV0073_CTRL_CMD_SYSTEM_GET_SUPPORTED, sizeof(*ctrl));
14791cf5940bSBen Skeggs 	if (IS_ERR(ctrl))
14801cf5940bSBen Skeggs 		return PTR_ERR(ctrl);
14811cf5940bSBen Skeggs 
14821cf5940bSBen Skeggs 	*pmask = ctrl->displayMask;
14831cf5940bSBen Skeggs 	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
14841cf5940bSBen Skeggs 	return 0;
14851cf5940bSBen Skeggs }
14861cf5940bSBen Skeggs 
14871cf5940bSBen Skeggs static int
r535_disp_get_static_info(struct nvkm_disp * disp)14886854ce2cSBen Skeggs r535_disp_get_static_info(struct nvkm_disp *disp)
14896854ce2cSBen Skeggs {
14906854ce2cSBen Skeggs 	NV2080_CTRL_INTERNAL_DISPLAY_GET_STATIC_INFO_PARAMS *ctrl;
14916854ce2cSBen Skeggs 	struct nvkm_gsp *gsp = disp->rm.objcom.client->gsp;
14926854ce2cSBen Skeggs 
14936854ce2cSBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,
14946854ce2cSBen Skeggs 				   NV2080_CTRL_CMD_INTERNAL_DISPLAY_GET_STATIC_INFO,
14956854ce2cSBen Skeggs 				   sizeof(*ctrl));
14966854ce2cSBen Skeggs 	if (IS_ERR(ctrl))
14976854ce2cSBen Skeggs 		return PTR_ERR(ctrl);
14986854ce2cSBen Skeggs 
14996854ce2cSBen Skeggs 	disp->wndw.mask = ctrl->windowPresentMask;
15006854ce2cSBen Skeggs 	disp->wndw.nr = fls(disp->wndw.mask);
15016854ce2cSBen Skeggs 
15026854ce2cSBen Skeggs 	nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, ctrl);
15036854ce2cSBen Skeggs 	return 0;
15046854ce2cSBen Skeggs }
15056854ce2cSBen Skeggs 
15066854ce2cSBen Skeggs static int
r535_disp_oneinit(struct nvkm_disp * disp)15079e994444SBen Skeggs r535_disp_oneinit(struct nvkm_disp *disp)
15089e994444SBen Skeggs {
15099e994444SBen Skeggs 	struct nvkm_device *device = disp->engine.subdev.device;
15109e994444SBen Skeggs 	struct nvkm_gsp *gsp = device->gsp;
15116854ce2cSBen Skeggs 	const struct nvkm_rm_api *rmapi = gsp->rm->api;
15129e994444SBen Skeggs 	NV2080_CTRL_INTERNAL_DISPLAY_WRITE_INST_MEM_PARAMS *ctrl;
15131cf5940bSBen Skeggs 	unsigned long mask;
15149e994444SBen Skeggs 	int ret, i;
15159e994444SBen Skeggs 
15169e994444SBen Skeggs 	/* RAMIN. */
15179e994444SBen Skeggs 	ret = nvkm_gpuobj_new(device, 0x10000, 0x10000, false, NULL, &disp->inst);
15189e994444SBen Skeggs 	if (ret)
15199e994444SBen Skeggs 		return ret;
15209e994444SBen Skeggs 
15219e994444SBen Skeggs 	if (WARN_ON(nvkm_memory_target(disp->inst->memory) != NVKM_MEM_TARGET_VRAM))
15229e994444SBen Skeggs 		return -EINVAL;
15239e994444SBen Skeggs 
15249e994444SBen Skeggs 	ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,
15259e994444SBen Skeggs 				    NV2080_CTRL_CMD_INTERNAL_DISPLAY_WRITE_INST_MEM,
15269e994444SBen Skeggs 				    sizeof(*ctrl));
15279e994444SBen Skeggs 	if (IS_ERR(ctrl))
15289e994444SBen Skeggs 		return PTR_ERR(ctrl);
15299e994444SBen Skeggs 
15309e994444SBen Skeggs 	ctrl->instMemPhysAddr = nvkm_memory_addr(disp->inst->memory);
15319e994444SBen Skeggs 	ctrl->instMemSize = nvkm_memory_size(disp->inst->memory);
15329e994444SBen Skeggs 	ctrl->instMemAddrSpace = ADDR_FBMEM;
15339e994444SBen Skeggs 	ctrl->instMemCpuCacheAttr = NV_MEMORY_WRITECOMBINED;
15349e994444SBen Skeggs 
15359e994444SBen Skeggs 	ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);
15369e994444SBen Skeggs 	if (ret)
15379e994444SBen Skeggs 		return ret;
15389e994444SBen Skeggs 
15399e994444SBen Skeggs 	/* OBJs. */
15409e994444SBen Skeggs 	ret = nvkm_gsp_client_device_ctor(gsp, &disp->rm.client, &disp->rm.device);
15419e994444SBen Skeggs 	if (ret)
15429e994444SBen Skeggs 		return ret;
15439e994444SBen Skeggs 
154438cafe9bSBen Skeggs 	ret = nvkm_gsp_rm_alloc(&disp->rm.device.object, NVKM_RM_DISP, NV04_DISPLAY_COMMON, 0,
15459e994444SBen Skeggs 				&disp->rm.objcom);
15469e994444SBen Skeggs 	if (ret)
15479e994444SBen Skeggs 		return ret;
15489e994444SBen Skeggs 
15496854ce2cSBen Skeggs 	ret = rmapi->disp->get_static_info(disp);
15506854ce2cSBen Skeggs 	if (ret)
15516854ce2cSBen Skeggs 		return ret;
15529e994444SBen Skeggs 
15539e994444SBen Skeggs 	/* */
15549e994444SBen Skeggs 	{
15559e994444SBen Skeggs #if defined(CONFIG_ACPI) && defined(CONFIG_X86)
15569e994444SBen Skeggs 		NV2080_CTRL_INTERNAL_INIT_BRIGHTC_STATE_LOAD_PARAMS *ctrl;
15579e994444SBen Skeggs 		struct nvkm_gsp_object *subdevice = &disp->rm.client.gsp->internal.device.subdevice;
15589e994444SBen Skeggs 
15599e994444SBen Skeggs 		ctrl = nvkm_gsp_rm_ctrl_get(subdevice,
15609e994444SBen Skeggs 					    NV2080_CTRL_CMD_INTERNAL_INIT_BRIGHTC_STATE_LOAD,
15619e994444SBen Skeggs 					    sizeof(*ctrl));
15629e994444SBen Skeggs 		if (IS_ERR(ctrl))
15639e994444SBen Skeggs 			return PTR_ERR(ctrl);
15649e994444SBen Skeggs 
15659e994444SBen Skeggs 		ctrl->status = 0x56; /* NV_ERR_NOT_SUPPORTED */
15669e994444SBen Skeggs 
15679e994444SBen Skeggs 		{
15689e994444SBen Skeggs 			const guid_t NBCI_DSM_GUID =
15699e994444SBen Skeggs 				GUID_INIT(0xD4A50B75, 0x65C7, 0x46F7,
15709e994444SBen Skeggs 					  0xBF, 0xB7, 0x41, 0x51, 0x4C, 0xEA, 0x02, 0x44);
15719e994444SBen Skeggs 			u64 NBCI_DSM_REV = 0x00000102;
15729e994444SBen Skeggs 			const guid_t NVHG_DSM_GUID =
15739e994444SBen Skeggs 				GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,
15749e994444SBen Skeggs 					  0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
15759e994444SBen Skeggs 			u64 NVHG_DSM_REV = 0x00000102;
15769e994444SBen Skeggs 			acpi_handle handle = ACPI_HANDLE(device->dev);
15779e994444SBen Skeggs 
15789e994444SBen Skeggs 			if (handle && acpi_has_method(handle, "_DSM")) {
15799e994444SBen Skeggs 				bool nbci = acpi_check_dsm(handle, &NBCI_DSM_GUID, NBCI_DSM_REV,
15809e994444SBen Skeggs 						           1ULL << 0x00000014);
15819e994444SBen Skeggs 				bool nvhg = acpi_check_dsm(handle, &NVHG_DSM_GUID, NVHG_DSM_REV,
15829e994444SBen Skeggs 						           1ULL << 0x00000014);
15839e994444SBen Skeggs 
15849e994444SBen Skeggs 				if (nbci || nvhg) {
15859e994444SBen Skeggs 					union acpi_object argv4 = {
15869e994444SBen Skeggs 						.buffer.type    = ACPI_TYPE_BUFFER,
15879e994444SBen Skeggs 						.buffer.length  = sizeof(ctrl->backLightData),
15889e994444SBen Skeggs 						.buffer.pointer = kmalloc(argv4.buffer.length, GFP_KERNEL),
15899e994444SBen Skeggs 					}, *obj;
15909e994444SBen Skeggs 
15919e994444SBen Skeggs 					obj = acpi_evaluate_dsm(handle, nbci ? &NBCI_DSM_GUID : &NVHG_DSM_GUID,
15929e994444SBen Skeggs 								0x00000102, 0x14, &argv4);
15939e994444SBen Skeggs 					if (!obj) {
15949e994444SBen Skeggs 						acpi_handle_info(handle, "failed to evaluate _DSM\n");
15959e994444SBen Skeggs 					} else {
15969e994444SBen Skeggs 						for (int i = 0; i < obj->package.count; i++) {
15979e994444SBen Skeggs 							union acpi_object *elt = &obj->package.elements[i];
15989e994444SBen Skeggs 							u32 size;
15999e994444SBen Skeggs 
16009e994444SBen Skeggs 							if (elt->integer.value & ~0xffffffffULL)
16019e994444SBen Skeggs 								size = 8;
16029e994444SBen Skeggs 							else
16039e994444SBen Skeggs 								size = 4;
16049e994444SBen Skeggs 
16059e994444SBen Skeggs 							memcpy(&ctrl->backLightData[ctrl->backLightDataSize], &elt->integer.value, size);
16069e994444SBen Skeggs 							ctrl->backLightDataSize += size;
16079e994444SBen Skeggs 						}
16089e994444SBen Skeggs 
16099e994444SBen Skeggs 						ctrl->status = 0;
16109e994444SBen Skeggs 						ACPI_FREE(obj);
16119e994444SBen Skeggs 					}
16129e994444SBen Skeggs 
16139e994444SBen Skeggs 					kfree(argv4.buffer.pointer);
16149e994444SBen Skeggs 				}
16159e994444SBen Skeggs 			}
16169e994444SBen Skeggs 		}
16179e994444SBen Skeggs 
16189e994444SBen Skeggs 		ret = nvkm_gsp_rm_ctrl_wr(subdevice, ctrl);
16199e994444SBen Skeggs 		if (ret)
16209e994444SBen Skeggs 			return ret;
16219e994444SBen Skeggs #endif
16229e994444SBen Skeggs 	}
16239e994444SBen Skeggs 
16249e994444SBen Skeggs 	/* */
16259e994444SBen Skeggs 	{
16269e994444SBen Skeggs 		NV0073_CTRL_CMD_DP_SET_MANUAL_DISPLAYPORT_PARAMS *ctrl;
16279e994444SBen Skeggs 
16289e994444SBen Skeggs 		ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,
16299e994444SBen Skeggs 					    NV0073_CTRL_CMD_DP_SET_MANUAL_DISPLAYPORT,
16309e994444SBen Skeggs 					    sizeof(*ctrl));
16319e994444SBen Skeggs 		if (IS_ERR(ctrl))
16329e994444SBen Skeggs 			return PTR_ERR(ctrl);
16339e994444SBen Skeggs 
16349e994444SBen Skeggs 		ret = nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);
16359e994444SBen Skeggs 		if (ret)
16369e994444SBen Skeggs 			return ret;
16379e994444SBen Skeggs 	}
16389e994444SBen Skeggs 
16399e994444SBen Skeggs 	/* */
16409e994444SBen Skeggs 	{
16419e994444SBen Skeggs 		NV0073_CTRL_SYSTEM_GET_NUM_HEADS_PARAMS *ctrl;
16429e994444SBen Skeggs 
16439e994444SBen Skeggs 		ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,
16449e994444SBen Skeggs 					   NV0073_CTRL_CMD_SYSTEM_GET_NUM_HEADS, sizeof(*ctrl));
16459e994444SBen Skeggs 		if (IS_ERR(ctrl))
16469e994444SBen Skeggs 			return PTR_ERR(ctrl);
16479e994444SBen Skeggs 
16489e994444SBen Skeggs 		disp->head.nr = ctrl->numHeads;
16499e994444SBen Skeggs 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
16509e994444SBen Skeggs 	}
16519e994444SBen Skeggs 
16529e994444SBen Skeggs 	/* */
16539e994444SBen Skeggs 	{
16549e994444SBen Skeggs 		NV0073_CTRL_SPECIFIC_GET_ALL_HEAD_MASK_PARAMS *ctrl;
16559e994444SBen Skeggs 
16569e994444SBen Skeggs 		ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,
16579e994444SBen Skeggs 					   NV0073_CTRL_CMD_SPECIFIC_GET_ALL_HEAD_MASK,
16589e994444SBen Skeggs 					   sizeof(*ctrl));
16599e994444SBen Skeggs 		if (IS_ERR(ctrl))
16609e994444SBen Skeggs 			return PTR_ERR(ctrl);
16619e994444SBen Skeggs 
16629e994444SBen Skeggs 		disp->head.mask = ctrl->headMask;
16639e994444SBen Skeggs 		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);
16649e994444SBen Skeggs 
16659e994444SBen Skeggs 		for_each_set_bit(i, &disp->head.mask, disp->head.nr) {
16669e994444SBen Skeggs 			ret = nvkm_head_new_(&r535_head, disp, i);
16679e994444SBen Skeggs 			if (ret)
16689e994444SBen Skeggs 				return ret;
16699e994444SBen Skeggs 		}
16709e994444SBen Skeggs 	}
16719e994444SBen Skeggs 
16729e994444SBen Skeggs 	disp->sor.nr = disp->func->sor.cnt(disp, &disp->sor.mask);
16739e994444SBen Skeggs 	nvkm_debug(&disp->engine.subdev, "   SOR(s): %d (%02lx)\n", disp->sor.nr, disp->sor.mask);
16749e994444SBen Skeggs 	for_each_set_bit(i, &disp->sor.mask, disp->sor.nr) {
16759e994444SBen Skeggs 		ret = disp->func->sor.new(disp, i);
16769e994444SBen Skeggs 		if (ret)
16779e994444SBen Skeggs 			return ret;
16789e994444SBen Skeggs 	}
16799e994444SBen Skeggs 
16801cf5940bSBen Skeggs 	ret = rmapi->disp->get_supported(disp, &mask);
16811cf5940bSBen Skeggs 	if (ret)
16821cf5940bSBen Skeggs 		return ret;
16839e994444SBen Skeggs 
16849e994444SBen Skeggs 	for_each_set_bit(i, &mask, 32) {
16859e994444SBen Skeggs 		ret = r535_outp_new(disp, i);
16869e994444SBen Skeggs 		if (ret)
16879e994444SBen Skeggs 			return ret;
16889e994444SBen Skeggs 	}
16899e994444SBen Skeggs 
16909e994444SBen Skeggs 	ret = nvkm_event_init(&r535_disp_event, &gsp->subdev, 3, 32, &disp->rm.event);
16919e994444SBen Skeggs 	if (WARN_ON(ret))
16929e994444SBen Skeggs 		return ret;
16939e994444SBen Skeggs 
16949e994444SBen Skeggs 	ret = nvkm_gsp_device_event_ctor(&disp->rm.device, 0x007e0000, NV2080_NOTIFIERS_HOTPLUG,
16959e994444SBen Skeggs 					 r535_disp_hpd, &disp->rm.hpd);
16969e994444SBen Skeggs 	if (ret)
16979e994444SBen Skeggs 		return ret;
16989e994444SBen Skeggs 
16999e994444SBen Skeggs 	ret = nvkm_gsp_device_event_ctor(&disp->rm.device, 0x007e0001, NV2080_NOTIFIERS_DP_IRQ,
17009e994444SBen Skeggs 					 r535_disp_irq, &disp->rm.irq);
17019e994444SBen Skeggs 	if (ret)
17029e994444SBen Skeggs 		return ret;
17039e994444SBen Skeggs 
17049e994444SBen Skeggs 	/* RAMHT. */
17059e994444SBen Skeggs 	ret = nvkm_ramht_new(device, disp->func->ramht_size ? disp->func->ramht_size :
17069e994444SBen Skeggs 			     0x1000, 0, disp->inst, &disp->ramht);
17079e994444SBen Skeggs 	if (ret)
17089e994444SBen Skeggs 		return ret;
17099e994444SBen Skeggs 
17109e994444SBen Skeggs 	ret = nvkm_gsp_intr_stall(gsp, disp->engine.subdev.type, disp->engine.subdev.inst);
17119e994444SBen Skeggs 	if (ret < 0)
17129e994444SBen Skeggs 		return ret;
17139e994444SBen Skeggs 
17149e994444SBen Skeggs 	ret = nvkm_inth_add(&device->vfn->intr, ret, NVKM_INTR_PRIO_NORMAL, &disp->engine.subdev,
17159e994444SBen Skeggs 			    r535_disp_intr, &disp->engine.subdev.inth);
17169e994444SBen Skeggs 	if (ret)
17179e994444SBen Skeggs 		return ret;
17189e994444SBen Skeggs 
17199e994444SBen Skeggs 	nvkm_inth_allow(&disp->engine.subdev.inth);
17209e994444SBen Skeggs 	return 0;
17219e994444SBen Skeggs }
17229e994444SBen Skeggs 
17239e994444SBen Skeggs static void
r535_disp_dtor(struct nvkm_disp * disp)17249e994444SBen Skeggs r535_disp_dtor(struct nvkm_disp *disp)
17259e994444SBen Skeggs {
17269e994444SBen Skeggs 	kfree(disp->func);
17279e994444SBen Skeggs }
17289e994444SBen Skeggs 
17299e994444SBen Skeggs int
r535_disp_new(const struct nvkm_disp_func * hw,struct nvkm_device * device,enum nvkm_subdev_type type,int inst,struct nvkm_disp ** pdisp)17309e994444SBen Skeggs r535_disp_new(const struct nvkm_disp_func *hw, struct nvkm_device *device,
17319e994444SBen Skeggs 	      enum nvkm_subdev_type type, int inst, struct nvkm_disp **pdisp)
17329e994444SBen Skeggs {
17330fac5141SBen Skeggs 	const struct nvkm_rm_gpu *gpu = device->gsp->rm->gpu;
17349e994444SBen Skeggs 	struct nvkm_disp_func *rm;
17359e994444SBen Skeggs 	int ret;
17369e994444SBen Skeggs 
17379e994444SBen Skeggs 	if (!(rm = kzalloc(sizeof(*rm) + 6 * sizeof(rm->user[0]), GFP_KERNEL)))
17389e994444SBen Skeggs 		return -ENOMEM;
17399e994444SBen Skeggs 
17409e994444SBen Skeggs 	rm->dtor = r535_disp_dtor;
17419e994444SBen Skeggs 	rm->oneinit = r535_disp_oneinit;
17429e994444SBen Skeggs 	rm->init = r535_disp_init;
17439e994444SBen Skeggs 	rm->fini = r535_disp_fini;
17449e994444SBen Skeggs 	rm->uevent = hw->uevent;
17459e994444SBen Skeggs 	rm->sor.cnt = r535_sor_cnt;
17469e994444SBen Skeggs 	rm->sor.new = r535_sor_new;
17479e994444SBen Skeggs 	rm->ramht_size = hw->ramht_size;
17489e994444SBen Skeggs 
17490fac5141SBen Skeggs 	rm->root.oclass = gpu->disp.class.root;
17509e994444SBen Skeggs 
17510fac5141SBen Skeggs 	rm->user[0].base.oclass = gpu->disp.class.caps;
17520fac5141SBen Skeggs 	rm->user[0].ctor = gv100_disp_caps_new;
17530fac5141SBen Skeggs 
17540fac5141SBen Skeggs 	rm->user[1].base.oclass = gpu->disp.class.core;
17550fac5141SBen Skeggs 	rm->user[1].ctor = nvkm_disp_core_new;
17560fac5141SBen Skeggs 	rm->user[1].chan = &r535_core;
17570fac5141SBen Skeggs 
17580fac5141SBen Skeggs 	rm->user[2].base.oclass = gpu->disp.class.wndw;
17590fac5141SBen Skeggs 	rm->user[2].ctor = nvkm_disp_wndw_new;
17600fac5141SBen Skeggs 	rm->user[2].chan = &r535_wndw;
17610fac5141SBen Skeggs 
17620fac5141SBen Skeggs 	rm->user[3].base.oclass = gpu->disp.class.wimm;
17630fac5141SBen Skeggs 	rm->user[3].ctor = nvkm_disp_wndw_new;
17640fac5141SBen Skeggs 	rm->user[3].chan = &r535_wimm;
17650fac5141SBen Skeggs 
17660fac5141SBen Skeggs 	rm->user[4].base.oclass = gpu->disp.class.curs;
17670fac5141SBen Skeggs 	rm->user[4].ctor = nvkm_disp_chan_new;
17680fac5141SBen Skeggs 	rm->user[4].chan = &r535_curs;
17699e994444SBen Skeggs 
17709e994444SBen Skeggs 	ret = nvkm_disp_new_(rm, device, type, inst, pdisp);
17719e994444SBen Skeggs 	if (ret)
17729e994444SBen Skeggs 		kfree(rm);
17739e994444SBen Skeggs 
17749e994444SBen Skeggs 	mutex_init(&(*pdisp)->super.mutex); //XXX
17759e994444SBen Skeggs 	return ret;
17769e994444SBen Skeggs }
17778f8d9bcaSBen Skeggs 
17788f8d9bcaSBen Skeggs const struct nvkm_rm_api_disp
17798f8d9bcaSBen Skeggs r535_disp = {
17806854ce2cSBen Skeggs 	.get_static_info = r535_disp_get_static_info,
17811cf5940bSBen Skeggs 	.get_supported = r535_disp_get_supported,
1782bfbae411SBen Skeggs 	.get_connect_state = r535_disp_get_connect_state,
1783cf6b2b5eSBen Skeggs 	.get_active = r535_disp_get_active,
17848f8d9bcaSBen Skeggs 	.bl_ctrl = r535_bl_ctrl,
1785a3f32329SBen Skeggs 	.dp = {
178637a82fa3SBen Skeggs 		.get_caps = r535_dp_get_caps,
1787a3f32329SBen Skeggs 		.set_indexed_link_rates = r535_dp_set_indexed_link_rates,
1788e0ed9434SBen Skeggs 	},
1789e0ed9434SBen Skeggs 	.chan = {
1790e0ed9434SBen Skeggs 		.set_pushbuf = r535_disp_chan_set_pushbuf,
1791*f82fb646SBen Skeggs 		.dmac_alloc = r535_dmac_alloc,
1792a3f32329SBen Skeggs 	}
17938f8d9bcaSBen Skeggs };
1794