brintos

brintos / linux-shallow public Read only

0
0
Text · 43.8 KiB · 99110ab Raw
1726 lines · c
1/*2 * Copyright 2023 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 */22#include "priv.h"23#include "chan.h"24#include "conn.h"25#include "dp.h"26#include "head.h"27#include "ior.h"28#include "outp.h"29 30#include <core/ramht.h>31#include <subdev/bios.h>32#include <subdev/bios/conn.h>33#include <subdev/gsp.h>34#include <subdev/mmu.h>35#include <subdev/vfn.h>36 37#include <nvhw/drf.h>38 39#include <nvrm/nvtypes.h>40#include <nvrm/535.113.01/common/sdk/nvidia/inc/class/cl2080_notification.h>41#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073dfp.h>42#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073dp.h>43#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073specific.h>44#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073system.h>45#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080internal.h>46#include <nvrm/535.113.01/common/sdk/nvidia/inc/nvos.h>47#include <nvrm/535.113.01/nvidia/generated/g_allclasses.h>48#include <nvrm/535.113.01/nvidia/generated/g_mem_desc_nvoc.h>49#include <nvrm/535.113.01/nvidia/inc/kernel/os/nv_memory_type.h>50 51#include <linux/acpi.h>52 53static u6454r535_chan_user(struct nvkm_disp_chan *chan, u64 *psize)55{56	switch (chan->object.oclass & 0xff) {57	case 0x7d: *psize = 0x10000; return 0x680000;58	case 0x7e: *psize = 0x01000; return 0x690000 + (chan->head * *psize);59	case 0x7b: *psize = 0x01000; return 0x6b0000 + (chan->head * *psize);60	case 0x7a: *psize = 0x01000; return 0x6d8000 + (chan->head * *psize);61	default:62		BUG_ON(1);63		break;64	}65 66	return 0ULL;67}68 69static void70r535_chan_intr(struct nvkm_disp_chan *chan, bool en)71{72}73 74static void75r535_chan_fini(struct nvkm_disp_chan *chan)76{77	nvkm_gsp_rm_free(&chan->rm.object);78}79 80static int81r535_chan_push(struct nvkm_disp_chan *chan)82{83	struct nvkm_gsp *gsp = chan->disp->engine.subdev.device->gsp;84	NV2080_CTRL_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER_PARAMS *ctrl;85 86	ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,87				    NV2080_CTRL_CMD_INTERNAL_DISPLAY_CHANNEL_PUSHBUFFER,88				    sizeof(*ctrl));89	if (IS_ERR(ctrl))90		return PTR_ERR(ctrl);91 92	if (chan->memory) {93		switch (nvkm_memory_target(chan->memory)) {94		case NVKM_MEM_TARGET_NCOH:95			ctrl->addressSpace = ADDR_SYSMEM;96			ctrl->cacheSnoop = 0;97			break;98		case NVKM_MEM_TARGET_HOST:99			ctrl->addressSpace = ADDR_SYSMEM;100			ctrl->cacheSnoop = 1;101			break;102		case NVKM_MEM_TARGET_VRAM:103			ctrl->addressSpace = ADDR_FBMEM;104			break;105		default:106			WARN_ON(1);107			return -EINVAL;108		}109 110		ctrl->physicalAddr = nvkm_memory_addr(chan->memory);111		ctrl->limit = nvkm_memory_size(chan->memory) - 1;112	}113 114	ctrl->hclass = chan->object.oclass;115	ctrl->channelInstance = chan->head;116	ctrl->valid = ((chan->object.oclass & 0xff) != 0x7a) ? 1 : 0;117 118	return nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);119}120 121static int122r535_curs_init(struct nvkm_disp_chan *chan)123{124	NV50VAIO_CHANNELPIO_ALLOCATION_PARAMETERS *args;125	int ret;126 127	ret = r535_chan_push(chan);128	if (ret)129		return ret;130 131	args = nvkm_gsp_rm_alloc_get(&chan->disp->rm.object,132				     (chan->object.oclass << 16) | chan->head,133				     chan->object.oclass, sizeof(*args), &chan->rm.object);134	if (IS_ERR(args))135		return PTR_ERR(args);136 137	args->channelInstance = chan->head;138 139	return nvkm_gsp_rm_alloc_wr(&chan->rm.object, args);140}141 142static const struct nvkm_disp_chan_func143r535_curs_func = {144	.init = r535_curs_init,145	.fini = r535_chan_fini,146	.intr = r535_chan_intr,147	.user = r535_chan_user,148};149 150static const struct nvkm_disp_chan_user151r535_curs = {152	.func = &r535_curs_func,153	.user = 73,154};155 156static int157r535_dmac_bind(struct nvkm_disp_chan *chan, struct nvkm_object *object, u32 handle)158{159	return nvkm_ramht_insert(chan->disp->ramht, object, chan->chid.user, -9, handle,160				 chan->chid.user << 25 |161				 (chan->disp->rm.client.object.handle & 0x3fff));162}163 164static void165r535_dmac_fini(struct nvkm_disp_chan *chan)166{167	struct nvkm_device *device = chan->disp->engine.subdev.device;168	const u32 uoff = (chan->chid.user - 1) * 0x1000;169 170	chan->suspend_put = nvkm_rd32(device, 0x690000 + uoff);171	r535_chan_fini(chan);172}173 174static int175r535_dmac_init(struct nvkm_disp_chan *chan)176{177	NV50VAIO_CHANNELDMA_ALLOCATION_PARAMETERS *args;178	int ret;179 180	ret = r535_chan_push(chan);181	if (ret)182		return ret;183 184	args = nvkm_gsp_rm_alloc_get(&chan->disp->rm.object,185				     (chan->object.oclass << 16) | chan->head,186				     chan->object.oclass, sizeof(*args), &chan->rm.object);187	if (IS_ERR(args))188		return PTR_ERR(args);189 190	args->channelInstance = chan->head;191	args->offset = chan->suspend_put;192 193	return nvkm_gsp_rm_alloc_wr(&chan->rm.object, args);194}195 196static int197r535_dmac_push(struct nvkm_disp_chan *chan, u64 memory)198{199	chan->memory = nvkm_umem_search(chan->object.client, memory);200	if (IS_ERR(chan->memory))201		return PTR_ERR(chan->memory);202 203	return 0;204}205 206static const struct nvkm_disp_chan_func207r535_dmac_func = {208	.push = r535_dmac_push,209	.init = r535_dmac_init,210	.fini = r535_dmac_fini,211	.intr = r535_chan_intr,212	.user = r535_chan_user,213	.bind = r535_dmac_bind,214};215 216static const struct nvkm_disp_chan_func217r535_wimm_func = {218	.push = r535_dmac_push,219	.init = r535_dmac_init,220	.fini = r535_dmac_fini,221	.intr = r535_chan_intr,222	.user = r535_chan_user,223};224 225static const struct nvkm_disp_chan_user226r535_wimm = {227	.func = &r535_wimm_func,228	.user = 33,229};230 231static const struct nvkm_disp_chan_user232r535_wndw = {233	.func = &r535_dmac_func,234	.user = 1,235};236 237static void238r535_core_fini(struct nvkm_disp_chan *chan)239{240	struct nvkm_device *device = chan->disp->engine.subdev.device;241 242	chan->suspend_put = nvkm_rd32(device, 0x680000);243	r535_chan_fini(chan);244}245 246static const struct nvkm_disp_chan_func247r535_core_func = {248	.push = r535_dmac_push,249	.init = r535_dmac_init,250	.fini = r535_core_fini,251	.intr = r535_chan_intr,252	.user = r535_chan_user,253	.bind = r535_dmac_bind,254};255 256static const struct nvkm_disp_chan_user257r535_core = {258	.func = &r535_core_func,259	.user = 0,260};261 262static int263r535_sor_bl_set(struct nvkm_ior *sor, int lvl)264{265	struct nvkm_disp *disp = sor->disp;266	NV0073_CTRL_SPECIFIC_BACKLIGHT_BRIGHTNESS_PARAMS *ctrl;267 268	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,269				    NV0073_CTRL_CMD_SPECIFIC_SET_BACKLIGHT_BRIGHTNESS,270				    sizeof(*ctrl));271	if (IS_ERR(ctrl))272		return PTR_ERR(ctrl);273 274	ctrl->displayId = BIT(sor->asy.outp->index);275	ctrl->brightness = lvl;276 277	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);278}279 280static int281r535_sor_bl_get(struct nvkm_ior *sor)282{283	struct nvkm_disp *disp = sor->disp;284	NV0073_CTRL_SPECIFIC_BACKLIGHT_BRIGHTNESS_PARAMS *ctrl;285	int ret, lvl;286 287	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,288				    NV0073_CTRL_CMD_SPECIFIC_GET_BACKLIGHT_BRIGHTNESS,289				    sizeof(*ctrl));290	if (IS_ERR(ctrl))291		return PTR_ERR(ctrl);292 293	ctrl->displayId = BIT(sor->asy.outp->index);294 295	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));296	if (ret) {297		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);298		return ret;299	}300 301	lvl = ctrl->brightness;302	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);303	return lvl;304}305 306static const struct nvkm_ior_func_bl307r535_sor_bl = {308	.get = r535_sor_bl_get,309	.set = r535_sor_bl_set,310};311 312static void313r535_sor_hda_eld(struct nvkm_ior *sor, int head, u8 *data, u8 size)314{315	struct nvkm_disp *disp = sor->disp;316	NV0073_CTRL_DFP_SET_ELD_AUDIO_CAP_PARAMS *ctrl;317 318	if (WARN_ON(size > sizeof(ctrl->bufferELD)))319		return;320 321	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,322				    NV0073_CTRL_CMD_DFP_SET_ELD_AUDIO_CAPS, sizeof(*ctrl));323	if (WARN_ON(IS_ERR(ctrl)))324		return;325 326	ctrl->displayId = BIT(sor->asy.outp->index);327	ctrl->numELDSize = size;328	memcpy(ctrl->bufferELD, data, size);329	ctrl->maxFreqSupported = 0; //XXX330	ctrl->ctrl  = NVDEF(NV0073, CTRL_DFP_ELD_AUDIO_CAPS_CTRL, PD, TRUE);331	ctrl->ctrl |= NVDEF(NV0073, CTRL_DFP_ELD_AUDIO_CAPS_CTRL, ELDV, TRUE);332	ctrl->deviceEntry = head;333 334	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));335}336 337static void338r535_sor_hda_hpd(struct nvkm_ior *sor, int head, bool present)339{340	struct nvkm_disp *disp = sor->disp;341	NV0073_CTRL_DFP_SET_ELD_AUDIO_CAP_PARAMS *ctrl;342 343	if (present)344		return;345 346	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,347				    NV0073_CTRL_CMD_DFP_SET_ELD_AUDIO_CAPS, sizeof(*ctrl));348	if (WARN_ON(IS_ERR(ctrl)))349		return;350 351	ctrl->displayId = BIT(sor->asy.outp->index);352	ctrl->deviceEntry = head;353 354	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));355}356 357static const struct nvkm_ior_func_hda358r535_sor_hda = {359	.hpd = r535_sor_hda_hpd,360	.eld = r535_sor_hda_eld,361};362 363static void364r535_sor_dp_audio_mute(struct nvkm_ior *sor, bool mute)365{366	struct nvkm_disp *disp = sor->disp;367	NV0073_CTRL_DP_SET_AUDIO_MUTESTREAM_PARAMS *ctrl;368 369	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,370				    NV0073_CTRL_CMD_DP_SET_AUDIO_MUTESTREAM, sizeof(*ctrl));371	if (WARN_ON(IS_ERR(ctrl)))372		return;373 374	ctrl->displayId = BIT(sor->asy.outp->index);375	ctrl->mute = mute;376	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));377}378 379static void380r535_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)381{382	struct nvkm_disp *disp = sor->disp;383	NV0073_CTRL_DFP_SET_AUDIO_ENABLE_PARAMS *ctrl;384 385	if (!enable)386		r535_sor_dp_audio_mute(sor, true);387 388	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,389				    NV0073_CTRL_CMD_DFP_SET_AUDIO_ENABLE, sizeof(*ctrl));390	if (WARN_ON(IS_ERR(ctrl)))391		return;392 393	ctrl->displayId = BIT(sor->asy.outp->index);394	ctrl->enable = enable;395	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));396 397	if (enable)398		r535_sor_dp_audio_mute(sor, false);399}400 401static void402r535_sor_dp_vcpi(struct nvkm_ior *sor, int head, u8 slot, u8 slot_nr, u16 pbn, u16 aligned_pbn)403{404	struct nvkm_disp *disp = sor->disp;405	struct NV0073_CTRL_CMD_DP_CONFIG_STREAM_PARAMS *ctrl;406 407	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,408				    NV0073_CTRL_CMD_DP_CONFIG_STREAM, sizeof(*ctrl));409	if (WARN_ON(IS_ERR(ctrl)))410		return;411 412	ctrl->subDeviceInstance = 0;413	ctrl->head = head;414	ctrl->sorIndex = sor->id;415	ctrl->dpLink = sor->asy.link == 2;416	ctrl->bEnableOverride = 1;417	ctrl->bMST = 1;418	ctrl->hBlankSym = 0;419	ctrl->vBlankSym = 0;420	ctrl->colorFormat = 0;421	ctrl->bEnableTwoHeadOneOr = 0;422	ctrl->singleHeadMultistreamMode = 0;423	ctrl->MST.slotStart = slot;424	ctrl->MST.slotEnd = slot + slot_nr - 1;425	ctrl->MST.PBN = pbn;426	ctrl->MST.Timeslice = aligned_pbn;427	ctrl->MST.sendACT = 0;428	ctrl->MST.singleHeadMSTPipeline = 0;429	ctrl->MST.bEnableAudioOverRightPanel = 0;430	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));431}432 433static int434r535_sor_dp_sst(struct nvkm_ior *sor, int head, bool ef,435		u32 watermark, u32 hblanksym, u32 vblanksym)436{437	struct nvkm_disp *disp = sor->disp;438	struct NV0073_CTRL_CMD_DP_CONFIG_STREAM_PARAMS *ctrl;439 440	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,441				    NV0073_CTRL_CMD_DP_CONFIG_STREAM, sizeof(*ctrl));442	if (IS_ERR(ctrl))443		return PTR_ERR(ctrl);444 445	ctrl->subDeviceInstance = 0;446	ctrl->head = head;447	ctrl->sorIndex = sor->id;448	ctrl->dpLink = sor->asy.link == 2;449	ctrl->bEnableOverride = 1;450	ctrl->bMST = 0;451	ctrl->hBlankSym = hblanksym;452	ctrl->vBlankSym = vblanksym;453	ctrl->colorFormat = 0;454	ctrl->bEnableTwoHeadOneOr = 0;455	ctrl->SST.bEnhancedFraming = ef;456	ctrl->SST.tuSize = 64;457	ctrl->SST.waterMark = watermark;458	ctrl->SST.bEnableAudioOverRightPanel = 0;459	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);460}461 462static const struct nvkm_ior_func_dp463r535_sor_dp = {464	.sst = r535_sor_dp_sst,465	.vcpi = r535_sor_dp_vcpi,466	.audio = r535_sor_dp_audio,467};468 469static void470r535_sor_hdmi_scdc(struct nvkm_ior *sor, u32 khz, bool support, bool scrambling,471		   bool scrambling_low_rates)472{473	struct nvkm_outp *outp = sor->asy.outp;474	struct nvkm_disp *disp = outp->disp;475	NV0073_CTRL_SPECIFIC_SET_HDMI_SINK_CAPS_PARAMS *ctrl;476 477	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,478				    NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_SINK_CAPS, sizeof(*ctrl));479	if (WARN_ON(IS_ERR(ctrl)))480		return;481 482	ctrl->displayId = BIT(outp->index);483	ctrl->caps = 0;484	if (support)485		ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, SCDC_SUPPORTED, TRUE);486	if (scrambling)487		ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, GT_340MHZ_CLOCK_SUPPORTED, TRUE);488	if (scrambling_low_rates)489		ctrl->caps |= NVDEF(NV0073_CTRL_CMD_SPECIFIC, SET_HDMI_SINK_CAPS, LTE_340MHZ_SCRAMBLING_SUPPORTED, TRUE);490 491	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));492}493 494static void495r535_sor_hdmi_ctrl_audio_mute(struct nvkm_outp *outp, bool mute)496{497	struct nvkm_disp *disp = outp->disp;498	NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_AUDIO_MUTESTREAM_PARAMS *ctrl;499 500	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,501				    NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_AUDIO_MUTESTREAM, sizeof(*ctrl));502	if (WARN_ON(IS_ERR(ctrl)))503		return;504 505	ctrl->displayId = BIT(outp->index);506	ctrl->mute = mute;507	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));508}509 510static void511r535_sor_hdmi_ctrl_audio(struct nvkm_outp *outp, bool enable)512{513	struct nvkm_disp *disp = outp->disp;514	NV0073_CTRL_SPECIFIC_SET_OD_PACKET_PARAMS *ctrl;515 516	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,517				    NV0073_CTRL_CMD_SPECIFIC_SET_OD_PACKET, sizeof(*ctrl));518	if (WARN_ON(IS_ERR(ctrl)))519		return;520 521	ctrl->displayId = BIT(outp->index);522	ctrl->transmitControl =523		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, ENABLE, YES) |524		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, OTHER_FRAME, DISABLE) |525		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, SINGLE_FRAME, DISABLE) |526		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, ON_HBLANK, DISABLE) |527		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, VIDEO_FMT, SW_CONTROLLED) |528		NVDEF(NV0073_CTRL_SPECIFIC, SET_OD_PACKET_TRANSMIT_CONTROL, RESERVED_LEGACY_MODE, NO);529	ctrl->packetSize = 10;530	ctrl->aPacket[0] = 0x03;531	ctrl->aPacket[1] = 0x00;532	ctrl->aPacket[2] = 0x00;533	ctrl->aPacket[3] = enable ? 0x10 : 0x01;534	ctrl->aPacket[4] = 0x00;535	ctrl->aPacket[5] = 0x00;536	ctrl->aPacket[6] = 0x00;537	ctrl->aPacket[7] = 0x00;538	ctrl->aPacket[8] = 0x00;539	ctrl->aPacket[9] = 0x00;540	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));541}542 543static void544r535_sor_hdmi_audio(struct nvkm_ior *sor, int head, bool enable)545{546	struct nvkm_device *device = sor->disp->engine.subdev.device;547	const u32 hdmi = head * 0x400;548 549	r535_sor_hdmi_ctrl_audio(sor->asy.outp, enable);550	r535_sor_hdmi_ctrl_audio_mute(sor->asy.outp, !enable);551 552	/* General Control (GCP). */553	nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000000);554	nvkm_wr32(device, 0x6f00cc + hdmi, !enable ? 0x00000001 : 0x00000010);555	nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000001);556}557 558static void559r535_sor_hdmi_ctrl(struct nvkm_ior *sor, int head, bool enable, u8 max_ac_packet, u8 rekey)560{561	struct nvkm_disp *disp = sor->disp;562	NV0073_CTRL_SPECIFIC_SET_HDMI_ENABLE_PARAMS *ctrl;563 564	if (!enable)565		return;566 567	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,568				    NV0073_CTRL_CMD_SPECIFIC_SET_HDMI_ENABLE, sizeof(*ctrl));569	if (WARN_ON(IS_ERR(ctrl)))570		return;571 572	ctrl->displayId = BIT(sor->asy.outp->index);573	ctrl->enable = enable;574 575	WARN_ON(nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl));576}577 578static const struct nvkm_ior_func_hdmi579r535_sor_hdmi = {580	.ctrl = r535_sor_hdmi_ctrl,581	.scdc = r535_sor_hdmi_scdc,582	/*TODO: SF_USER -> KMS. */583	.infoframe_avi = gv100_sor_hdmi_infoframe_avi,584	.infoframe_vsi = gv100_sor_hdmi_infoframe_vsi,585	.audio = r535_sor_hdmi_audio,586};587 588static const struct nvkm_ior_func589r535_sor = {590	.hdmi = &r535_sor_hdmi,591	.dp = &r535_sor_dp,592	.hda = &r535_sor_hda,593	.bl = &r535_sor_bl,594};595 596static int597r535_sor_new(struct nvkm_disp *disp, int id)598{599	return nvkm_ior_new_(&r535_sor, disp, SOR, id, true/*XXX: hda cap*/);600}601 602static int603r535_sor_cnt(struct nvkm_disp *disp, unsigned long *pmask)604{605	*pmask = 0xf;606	return 4;607}608 609static void610r535_head_vblank_put(struct nvkm_head *head)611{612	struct nvkm_device *device = head->disp->engine.subdev.device;613 614	nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000002, 0x00000000);615}616 617static void618r535_head_vblank_get(struct nvkm_head *head)619{620	struct nvkm_device *device = head->disp->engine.subdev.device;621 622	nvkm_wr32(device, 0x611800 + (head->id * 4), 0x00000002);623	nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000002, 0x00000002);624}625 626static void627r535_head_state(struct nvkm_head *head, struct nvkm_head_state *state)628{629}630 631static const struct nvkm_head_func632r535_head = {633	.state = r535_head_state,634	.vblank_get = r535_head_vblank_get,635	.vblank_put = r535_head_vblank_put,636};637 638static struct nvkm_conn *639r535_conn_new(struct nvkm_disp *disp, u32 id)640{641	NV0073_CTRL_SPECIFIC_GET_CONNECTOR_DATA_PARAMS *ctrl;642	struct nvbios_connE dcbE = {};643	struct nvkm_conn *conn;644	int ret, index;645 646	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,647				    NV0073_CTRL_CMD_SPECIFIC_GET_CONNECTOR_DATA, sizeof(*ctrl));648	if (IS_ERR(ctrl))649		return (void *)ctrl;650 651	ctrl->subDeviceInstance = 0;652	ctrl->displayId = BIT(id);653 654	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));655	if (ret) {656		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);657		return ERR_PTR(ret);658	}659 660	list_for_each_entry(conn, &disp->conns, head) {661		if (conn->index == ctrl->data[0].index) {662			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);663			return conn;664		}665	}666 667	dcbE.type = ctrl->data[0].type;668	index = ctrl->data[0].index;669	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);670 671	ret = nvkm_conn_new(disp, index, &dcbE, &conn);672	if (ret)673		return ERR_PTR(ret);674 675	list_add_tail(&conn->head, &disp->conns);676	return conn;677}678 679static void680r535_outp_release(struct nvkm_outp *outp)681{682	outp->disp->rm.assigned_sors &= ~BIT(outp->ior->id);683	outp->ior->asy.outp = NULL;684	outp->ior = NULL;685}686 687static int688r535_outp_acquire(struct nvkm_outp *outp, bool hda)689{690	struct nvkm_disp *disp = outp->disp;691	struct nvkm_ior *ior;692	NV0073_CTRL_DFP_ASSIGN_SOR_PARAMS *ctrl;693	int ret, or;694 695	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,696				    NV0073_CTRL_CMD_DFP_ASSIGN_SOR, sizeof(*ctrl));697	if (IS_ERR(ctrl))698		return PTR_ERR(ctrl);699 700	ctrl->subDeviceInstance = 0;701	ctrl->displayId = BIT(outp->index);702	ctrl->sorExcludeMask = disp->rm.assigned_sors;703	if (hda)704		ctrl->flags |= NVDEF(NV0073_CTRL, DFP_ASSIGN_SOR_FLAGS, AUDIO, OPTIMAL);705 706	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));707	if (ret) {708		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);709		return ret;710	}711 712	for (or = 0; or < ARRAY_SIZE(ctrl->sorAssignListWithTag); or++) {713		if (ctrl->sorAssignListWithTag[or].displayMask & BIT(outp->index)) {714			disp->rm.assigned_sors |= BIT(or);715			break;716		}717	}718 719	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);720 721	if (WARN_ON(or == ARRAY_SIZE(ctrl->sorAssignListWithTag)))722		return -EINVAL;723 724	ior = nvkm_ior_find(disp, SOR, or);725	if (WARN_ON(!ior))726		return -EINVAL;727 728	nvkm_outp_acquire_ior(outp, NVKM_OUTP_USER, ior);729	return 0;730}731 732static int733r535_disp_head_displayid(struct nvkm_disp *disp, int head, u32 *displayid)734{735	NV0073_CTRL_SYSTEM_GET_ACTIVE_PARAMS *ctrl;736	int ret;737 738	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,739				    NV0073_CTRL_CMD_SYSTEM_GET_ACTIVE, sizeof(*ctrl));740	if (IS_ERR(ctrl))741		return PTR_ERR(ctrl);742 743	ctrl->subDeviceInstance = 0;744	ctrl->head = head;745 746	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));747	if (ret) {748		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);749		return ret;750	}751 752	*displayid = ctrl->displayId;753	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);754	return 0;755}756 757static struct nvkm_ior *758r535_outp_inherit(struct nvkm_outp *outp)759{760	struct nvkm_disp *disp = outp->disp;761	struct nvkm_head *head;762	u32 displayid;763	int ret;764 765	list_for_each_entry(head, &disp->heads, head) {766		ret = r535_disp_head_displayid(disp, head->id, &displayid);767		if (WARN_ON(ret))768			return NULL;769 770		if (displayid == BIT(outp->index)) {771			NV0073_CTRL_SPECIFIC_OR_GET_INFO_PARAMS *ctrl;772			u32 id, proto;773			struct nvkm_ior *ior;774 775			ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,776						    NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO,777						    sizeof(*ctrl));778			if (IS_ERR(ctrl))779				return NULL;780 781			ctrl->subDeviceInstance = 0;782			ctrl->displayId = displayid;783 784			ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));785			if (ret) {786				nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);787				return NULL;788			}789 790			id = ctrl->index;791			proto = ctrl->protocol;792			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);793 794			ior = nvkm_ior_find(disp, SOR, id);795			if (WARN_ON(!ior))796				return NULL;797 798			switch (proto) {799			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_A:800				ior->arm.proto = TMDS;801				ior->arm.link = 1;802				break;803			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_B:804				ior->arm.proto = TMDS;805				ior->arm.link = 2;806				break;807			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DUAL_TMDS:808				ior->arm.proto = TMDS;809				ior->arm.link = 3;810				break;811			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A:812				ior->arm.proto = DP;813				ior->arm.link = 1;814				break;815			case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B:816				ior->arm.proto = DP;817				ior->arm.link = 2;818				break;819			default:820				WARN_ON(1);821				return NULL;822			}823 824			ior->arm.proto_evo = proto;825			ior->arm.head = BIT(head->id);826			disp->rm.assigned_sors |= BIT(ior->id);827			return ior;828		}829	}830 831	return NULL;832}833 834static int835r535_outp_dfp_get_info(struct nvkm_outp *outp)836{837	NV0073_CTRL_DFP_GET_INFO_PARAMS *ctrl;838	struct nvkm_disp *disp = outp->disp;839	int ret;840 841	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DFP_GET_INFO, sizeof(*ctrl));842	if (IS_ERR(ctrl))843		return PTR_ERR(ctrl);844 845	ctrl->displayId = BIT(outp->index);846 847	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));848	if (ret) {849		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);850		return ret;851	}852 853	nvkm_debug(&disp->engine.subdev, "DFP %08x: flags:%08x flags2:%08x\n",854		   ctrl->displayId, ctrl->flags, ctrl->flags2);855 856	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);857	return 0;858}859 860static int861r535_outp_detect(struct nvkm_outp *outp)862{863	NV0073_CTRL_SYSTEM_GET_CONNECT_STATE_PARAMS *ctrl;864	struct nvkm_disp *disp = outp->disp;865	int ret;866 867	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,868				    NV0073_CTRL_CMD_SYSTEM_GET_CONNECT_STATE, sizeof(*ctrl));869	if (IS_ERR(ctrl))870		return PTR_ERR(ctrl);871 872	ctrl->subDeviceInstance = 0;873	ctrl->displayMask = BIT(outp->index);874 875	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));876	if (ret) {877		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);878		return ret;879	}880 881	if (ctrl->displayMask & BIT(outp->index)) {882		ret = r535_outp_dfp_get_info(outp);883		if (ret == 0)884			ret = 1;885	} else {886		ret = 0;887	}888 889	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);890	return ret;891}892 893static int894r535_dp_mst_id_put(struct nvkm_outp *outp, u32 id)895{896	NV0073_CTRL_CMD_DP_TOPOLOGY_FREE_DISPLAYID_PARAMS *ctrl;897	struct nvkm_disp *disp = outp->disp;898 899	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,900				    NV0073_CTRL_CMD_DP_TOPOLOGY_FREE_DISPLAYID, sizeof(*ctrl));901	if (IS_ERR(ctrl))902		return PTR_ERR(ctrl);903 904	ctrl->subDeviceInstance = 0;905	ctrl->displayId = id;906	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);907}908 909static int910r535_dp_mst_id_get(struct nvkm_outp *outp, u32 *pid)911{912	NV0073_CTRL_CMD_DP_TOPOLOGY_ALLOCATE_DISPLAYID_PARAMS *ctrl;913	struct nvkm_disp *disp = outp->disp;914	int ret;915 916	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,917				    NV0073_CTRL_CMD_DP_TOPOLOGY_ALLOCATE_DISPLAYID,918				    sizeof(*ctrl));919	if (IS_ERR(ctrl))920		return PTR_ERR(ctrl);921 922	ctrl->subDeviceInstance = 0;923	ctrl->displayId = BIT(outp->index);924	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));925	if (ret) {926		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);927		return ret;928	}929 930	*pid = ctrl->displayIdAssigned;931	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);932	return 0;933}934 935static int936r535_dp_drive(struct nvkm_outp *outp, u8 lanes, u8 pe[4], u8 vs[4])937{938	NV0073_CTRL_DP_LANE_DATA_PARAMS *ctrl;939	struct nvkm_disp *disp = outp->disp;940 941	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,942				    NV0073_CTRL_CMD_DP_SET_LANE_DATA, sizeof(*ctrl));943	if (IS_ERR(ctrl))944		return PTR_ERR(ctrl);945 946	ctrl->displayId = BIT(outp->index);947	ctrl->numLanes = lanes;948	for (int i = 0; i < lanes; i++)949		ctrl->data[i] = NVVAL(NV0073_CTRL, DP_LANE_DATA,  PREEMPHASIS, pe[i]) |950				NVVAL(NV0073_CTRL, DP_LANE_DATA, DRIVECURRENT, vs[i]);951 952	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);953}954 955static int956r535_dp_train_target(struct nvkm_outp *outp, u8 target, bool mst, u8 link_nr, u8 link_bw)957{958	struct nvkm_disp *disp = outp->disp;959	NV0073_CTRL_DP_CTRL_PARAMS *ctrl;960	int ret, retries;961	u32 cmd, data;962 963	cmd = NVDEF(NV0073_CTRL, DP_CMD, SET_LANE_COUNT, TRUE) |964	      NVDEF(NV0073_CTRL, DP_CMD, SET_LINK_BW, TRUE) |965	      NVDEF(NV0073_CTRL, DP_CMD, TRAIN_PHY_REPEATER, YES);966	data = NVVAL(NV0073_CTRL, DP_DATA, SET_LANE_COUNT, link_nr) |967	       NVVAL(NV0073_CTRL, DP_DATA, SET_LINK_BW, link_bw) |968	       NVVAL(NV0073_CTRL, DP_DATA, TARGET, target);969 970	if (mst)971		cmd |= NVDEF(NV0073_CTRL, DP_CMD, SET_FORMAT_MODE, MULTI_STREAM);972 973	if (outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)974		cmd |= NVDEF(NV0073_CTRL, DP_CMD, SET_ENHANCED_FRAMING, TRUE);975 976	if (target == 0 &&977	     (outp->dp.dpcd[DPCD_RC02] & 0x20) &&978	    !(outp->dp.dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED))979		cmd |= NVDEF(NV0073_CTRL, DP_CMD, POST_LT_ADJ_REQ_GRANTED, YES);980 981	/* We should retry up to 3 times, but only if GSP asks politely */982	for (retries = 0; retries < 3; ++retries) {983		ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DP_CTRL,984					    sizeof(*ctrl));985		if (IS_ERR(ctrl))986			return PTR_ERR(ctrl);987 988		ctrl->subDeviceInstance = 0;989		ctrl->displayId = BIT(outp->index);990		ctrl->retryTimeMs = 0;991		ctrl->cmd = cmd;992		ctrl->data = data;993 994		ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));995		if ((ret == -EAGAIN || ret == -EBUSY) && ctrl->retryTimeMs) {996			/*997			 * Device (likely an eDP panel) isn't ready yet, wait for the time specified998			 * by GSP before retrying again999			 */1000			nvkm_debug(&disp->engine.subdev,1001				   "Waiting %dms for GSP LT panel delay before retrying\n",1002				   ctrl->retryTimeMs);1003			msleep(ctrl->retryTimeMs);1004			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1005		} else {1006			/* GSP didn't say to retry, or we were successful */1007			if (ctrl->err)1008				ret = -EIO;1009			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1010			break;1011		}1012	}1013 1014	return ret;1015}1016 1017static int1018r535_dp_train(struct nvkm_outp *outp, bool retrain)1019{1020	for (int target = outp->dp.lttprs; target >= 0; target--) {1021		int ret = r535_dp_train_target(outp, target, outp->dp.lt.mst,1022							     outp->dp.lt.nr,1023							     outp->dp.lt.bw);1024		if (ret)1025			return ret;1026	}1027 1028	return 0;1029}1030 1031static int1032r535_dp_rates(struct nvkm_outp *outp)1033{1034	NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES_PARAMS *ctrl;1035	struct nvkm_disp *disp = outp->disp;1036 1037	if (outp->conn->info.type != DCB_CONNECTOR_eDP ||1038	    !outp->dp.rates || outp->dp.rate[0].dpcd < 0)1039		return 0;1040 1041	if (WARN_ON(outp->dp.rates > ARRAY_SIZE(ctrl->linkRateTbl)))1042		return -EINVAL;1043 1044	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,1045				    NV0073_CTRL_CMD_DP_CONFIG_INDEXED_LINK_RATES, sizeof(*ctrl));1046	if (IS_ERR(ctrl))1047		return PTR_ERR(ctrl);1048 1049	ctrl->displayId = BIT(outp->index);1050	for (int i = 0; i < outp->dp.rates; i++)1051		ctrl->linkRateTbl[outp->dp.rate[i].dpcd] = outp->dp.rate[i].rate * 10 / 200;1052 1053	return nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);1054}1055 1056static int1057r535_dp_aux_xfer(struct nvkm_outp *outp, u8 type, u32 addr, u8 *data, u8 *psize)1058{1059	struct nvkm_disp *disp = outp->disp;1060	NV0073_CTRL_DP_AUXCH_CTRL_PARAMS *ctrl;1061	u8 size = *psize;1062	int ret;1063	int retries;1064 1065	for (retries = 0; retries < 3; ++retries) {1066		ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom, NV0073_CTRL_CMD_DP_AUXCH_CTRL, sizeof(*ctrl));1067		if (IS_ERR(ctrl))1068			return PTR_ERR(ctrl);1069 1070		ctrl->subDeviceInstance = 0;1071		ctrl->displayId = BIT(outp->index);1072		ctrl->bAddrOnly = !size;1073		ctrl->cmd = type;1074		if (ctrl->bAddrOnly) {1075			ctrl->cmd = NVDEF_SET(ctrl->cmd, NV0073_CTRL, DP_AUXCH_CMD, REQ_TYPE, WRITE);1076			ctrl->cmd = NVDEF_SET(ctrl->cmd, NV0073_CTRL, DP_AUXCH_CMD,  I2C_MOT, FALSE);1077		}1078		ctrl->addr = addr;1079		ctrl->size = !ctrl->bAddrOnly ? (size - 1) : 0;1080		memcpy(ctrl->data, data, size);1081 1082		ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));1083		if ((ret == -EAGAIN || ret == -EBUSY) && ctrl->retryTimeMs) {1084			/*1085			 * Device (likely an eDP panel) isn't ready yet, wait for the time specified1086			 * by GSP before retrying again1087			 */1088			nvkm_debug(&disp->engine.subdev,1089				   "Waiting %dms for GSP LT panel delay before retrying in AUX\n",1090				   ctrl->retryTimeMs);1091			msleep(ctrl->retryTimeMs);1092			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1093		} else {1094			memcpy(data, ctrl->data, size);1095			*psize = ctrl->size;1096			ret = ctrl->replyType;1097			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1098			break;1099		}1100	}1101	return ret;1102}1103 1104static int1105r535_dp_aux_pwr(struct nvkm_outp *outp, bool pu)1106{1107	return 0;1108}1109 1110static void1111r535_dp_release(struct nvkm_outp *outp)1112{1113	if (!outp->dp.lt.bw) {1114		if (!WARN_ON(!outp->dp.rates))1115			outp->dp.lt.bw = outp->dp.rate[0].rate / 27000;1116		else1117			outp->dp.lt.bw = 0x06;1118	}1119 1120	outp->dp.lt.nr = 0;1121 1122	r535_dp_train_target(outp, 0, outp->dp.lt.mst, outp->dp.lt.nr, outp->dp.lt.bw);1123	r535_outp_release(outp);1124}1125 1126static int1127r535_dp_acquire(struct nvkm_outp *outp, bool hda)1128{1129	int ret;1130 1131	ret = r535_outp_acquire(outp, hda);1132	if (ret)1133		return ret;1134 1135	return 0;1136}1137 1138static const struct nvkm_outp_func1139r535_dp = {1140	.detect = r535_outp_detect,1141	.inherit = r535_outp_inherit,1142	.acquire = r535_dp_acquire,1143	.release = r535_dp_release,1144	.dp.aux_pwr = r535_dp_aux_pwr,1145	.dp.aux_xfer = r535_dp_aux_xfer,1146	.dp.mst_id_get = r535_dp_mst_id_get,1147	.dp.mst_id_put = r535_dp_mst_id_put,1148	.dp.rates = r535_dp_rates,1149	.dp.train = r535_dp_train,1150	.dp.drive = r535_dp_drive,1151};1152 1153static int1154r535_tmds_edid_get(struct nvkm_outp *outp, u8 *data, u16 *psize)1155{1156	NV0073_CTRL_SPECIFIC_GET_EDID_V2_PARAMS *ctrl;1157	struct nvkm_disp *disp = outp->disp;1158	int ret = -E2BIG;1159 1160	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,1161				    NV0073_CTRL_CMD_SPECIFIC_GET_EDID_V2, sizeof(*ctrl));1162	if (IS_ERR(ctrl))1163		return PTR_ERR(ctrl);1164 1165	ctrl->subDeviceInstance = 0;1166	ctrl->displayId = BIT(outp->index);1167 1168	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));1169	if (ret) {1170		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1171		return ret;1172	}1173 1174	ret = -E2BIG;1175	if (ctrl->bufferSize <= *psize) {1176		memcpy(data, ctrl->edidBuffer, ctrl->bufferSize);1177		*psize = ctrl->bufferSize;1178		ret = 0;1179	}1180 1181	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1182	return ret;1183}1184 1185static const struct nvkm_outp_func1186r535_tmds = {1187	.detect = r535_outp_detect,1188	.inherit = r535_outp_inherit,1189	.acquire = r535_outp_acquire,1190	.release = r535_outp_release,1191	.edid_get = r535_tmds_edid_get,1192};1193 1194static int1195r535_outp_new(struct nvkm_disp *disp, u32 id)1196{1197	NV0073_CTRL_SPECIFIC_OR_GET_INFO_PARAMS *ctrl;1198	enum nvkm_ior_proto proto;1199	struct dcb_output dcbE = {};1200	struct nvkm_conn *conn;1201	struct nvkm_outp *outp;1202	u8 locn, link = 0;1203	int ret;1204 1205	ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,1206				    NV0073_CTRL_CMD_SPECIFIC_OR_GET_INFO, sizeof(*ctrl));1207	if (IS_ERR(ctrl))1208		return PTR_ERR(ctrl);1209 1210	ctrl->subDeviceInstance = 0;1211	ctrl->displayId = BIT(id);1212 1213	ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));1214	if (ret) {1215		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1216		return ret;1217	}1218 1219	switch (ctrl->type) {1220	case NV0073_CTRL_SPECIFIC_OR_TYPE_NONE:1221		return 0;1222	case NV0073_CTRL_SPECIFIC_OR_TYPE_SOR:1223		switch (ctrl->protocol) {1224		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_A:1225			proto = TMDS;1226			link = 1;1227			break;1228		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_SINGLE_TMDS_B:1229			proto = TMDS;1230			link = 2;1231			break;1232		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DUAL_TMDS:1233			proto = TMDS;1234			link = 3;1235			break;1236		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A:1237			proto = DP;1238			link = 1;1239			break;1240		case NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B:1241			proto = DP;1242			link = 2;1243			break;1244		default:1245			WARN_ON(1);1246			return -EINVAL;1247		}1248 1249		break;1250	default:1251		WARN_ON(1);1252		return -EINVAL;1253	}1254 1255	locn = ctrl->location;1256	nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1257 1258	conn = r535_conn_new(disp, id);1259	if (IS_ERR(conn))1260		return PTR_ERR(conn);1261 1262	switch (proto) {1263	case TMDS: dcbE.type = DCB_OUTPUT_TMDS; break;1264	case   DP: dcbE.type = DCB_OUTPUT_DP; break;1265	default:1266		WARN_ON(1);1267		return -EINVAL;1268	}1269 1270	dcbE.location = locn;1271	dcbE.connector = conn->index;1272	dcbE.heads = disp->head.mask;1273	dcbE.i2c_index = 0xff;1274	dcbE.link = dcbE.sorconf.link = link;1275 1276	if (proto == TMDS) {1277		ret = nvkm_outp_new_(&r535_tmds, disp, id, &dcbE, &outp);1278		if (ret)1279			return ret;1280	} else {1281		NV0073_CTRL_CMD_DP_GET_CAPS_PARAMS *ctrl;1282		bool mst, wm;1283 1284		ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,1285					    NV0073_CTRL_CMD_DP_GET_CAPS, sizeof(*ctrl));1286		if (IS_ERR(ctrl))1287			return PTR_ERR(ctrl);1288 1289		ctrl->sorIndex = ~0;1290 1291		ret = nvkm_gsp_rm_ctrl_push(&disp->rm.objcom, &ctrl, sizeof(*ctrl));1292		if (ret) {1293			nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1294			return ret;1295		}1296 1297		switch (NVVAL_GET(ctrl->maxLinkRate, NV0073_CTRL_CMD, DP_GET_CAPS, MAX_LINK_RATE)) {1298		case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_1_62:1299			dcbE.dpconf.link_bw = 0x06;1300			break;1301		case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_2_70:1302			dcbE.dpconf.link_bw = 0x0a;1303			break;1304		case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_5_40:1305			dcbE.dpconf.link_bw = 0x14;1306			break;1307		case NV0073_CTRL_CMD_DP_GET_CAPS_MAX_LINK_RATE_8_10:1308			dcbE.dpconf.link_bw = 0x1e;1309			break;1310		default:1311			dcbE.dpconf.link_bw = 0x00;1312			break;1313		}1314 1315		mst = ctrl->bIsMultistreamSupported;1316		wm = ctrl->bHasIncreasedWatermarkLimits;1317		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1318 1319		if (WARN_ON(!dcbE.dpconf.link_bw))1320			return -EINVAL;1321 1322		dcbE.dpconf.link_nr = 4;1323 1324		ret = nvkm_outp_new_(&r535_dp, disp, id, &dcbE, &outp);1325		if (ret)1326			return ret;1327 1328		outp->dp.mst = mst;1329		outp->dp.increased_wm = wm;1330	}1331 1332 1333	outp->conn = conn;1334	list_add_tail(&outp->head, &disp->outps);1335	return 0;1336}1337 1338static void1339r535_disp_irq(struct nvkm_gsp_event *event, void *repv, u32 repc)1340{1341	struct nvkm_disp *disp = container_of(event, typeof(*disp), rm.irq);1342	Nv2080DpIrqNotification *irq = repv;1343 1344	if (WARN_ON(repc < sizeof(*irq)))1345		return;1346 1347	nvkm_debug(&disp->engine.subdev, "event: dp irq displayId %08x\n", irq->displayId);1348 1349	if (irq->displayId)1350		nvkm_event_ntfy(&disp->rm.event, fls(irq->displayId) - 1, NVKM_DPYID_IRQ);1351}1352 1353static void1354r535_disp_hpd(struct nvkm_gsp_event *event, void *repv, u32 repc)1355{1356	struct nvkm_disp *disp = container_of(event, typeof(*disp), rm.hpd);1357	Nv2080HotplugNotification *hpd = repv;1358 1359	if (WARN_ON(repc < sizeof(*hpd)))1360		return;1361 1362	nvkm_debug(&disp->engine.subdev, "event: hpd plug %08x unplug %08x\n",1363		   hpd->plugDisplayMask, hpd->unplugDisplayMask);1364 1365	for (int i = 0; i < 31; i++) {1366		u32 mask = 0;1367 1368		if (hpd->plugDisplayMask & BIT(i))1369			mask |= NVKM_DPYID_PLUG;1370		if (hpd->unplugDisplayMask & BIT(i))1371			mask |= NVKM_DPYID_UNPLUG;1372 1373		if (mask)1374			nvkm_event_ntfy(&disp->rm.event, i, mask);1375	}1376}1377 1378static const struct nvkm_event_func1379r535_disp_event = {1380};1381 1382static void1383r535_disp_intr_head_timing(struct nvkm_disp *disp, int head)1384{1385	struct nvkm_subdev *subdev = &disp->engine.subdev;1386	struct nvkm_device *device = subdev->device;1387	u32 stat = nvkm_rd32(device, 0x611c00 + (head * 0x04));1388 1389	if (stat & 0x00000002) {1390		nvkm_disp_vblank(disp, head);1391 1392		nvkm_wr32(device, 0x611800 + (head * 0x04), 0x00000002);1393	}1394}1395 1396static irqreturn_t1397r535_disp_intr(struct nvkm_inth *inth)1398{1399	struct nvkm_disp *disp = container_of(inth, typeof(*disp), engine.subdev.inth);1400	struct nvkm_subdev *subdev = &disp->engine.subdev;1401	struct nvkm_device *device = subdev->device;1402	unsigned long mask = nvkm_rd32(device, 0x611ec0) & 0x000000ff;1403	int head;1404 1405	for_each_set_bit(head, &mask, 8)1406		r535_disp_intr_head_timing(disp, head);1407 1408	return IRQ_HANDLED;1409}1410 1411static void1412r535_disp_fini(struct nvkm_disp *disp, bool suspend)1413{1414	if (!disp->engine.subdev.use.enabled)1415		return;1416 1417	nvkm_gsp_rm_free(&disp->rm.object);1418 1419	if (!suspend) {1420		nvkm_gsp_event_dtor(&disp->rm.irq);1421		nvkm_gsp_event_dtor(&disp->rm.hpd);1422		nvkm_event_fini(&disp->rm.event);1423 1424		nvkm_gsp_rm_free(&disp->rm.objcom);1425		nvkm_gsp_device_dtor(&disp->rm.device);1426		nvkm_gsp_client_dtor(&disp->rm.client);1427	}1428}1429 1430static int1431r535_disp_init(struct nvkm_disp *disp)1432{1433	int ret;1434 1435	ret = nvkm_gsp_rm_alloc(&disp->rm.device.object, disp->func->root.oclass << 16,1436				disp->func->root.oclass, 0, &disp->rm.object);1437	if (ret)1438		return ret;1439 1440	return 0;1441}1442 1443static int1444r535_disp_oneinit(struct nvkm_disp *disp)1445{1446	struct nvkm_device *device = disp->engine.subdev.device;1447	struct nvkm_gsp *gsp = device->gsp;1448	NV2080_CTRL_INTERNAL_DISPLAY_WRITE_INST_MEM_PARAMS *ctrl;1449	int ret, i;1450 1451	/* RAMIN. */1452	ret = nvkm_gpuobj_new(device, 0x10000, 0x10000, false, NULL, &disp->inst);1453	if (ret)1454		return ret;1455 1456	if (WARN_ON(nvkm_memory_target(disp->inst->memory) != NVKM_MEM_TARGET_VRAM))1457		return -EINVAL;1458 1459	ctrl = nvkm_gsp_rm_ctrl_get(&gsp->internal.device.subdevice,1460				    NV2080_CTRL_CMD_INTERNAL_DISPLAY_WRITE_INST_MEM,1461				    sizeof(*ctrl));1462	if (IS_ERR(ctrl))1463		return PTR_ERR(ctrl);1464 1465	ctrl->instMemPhysAddr = nvkm_memory_addr(disp->inst->memory);1466	ctrl->instMemSize = nvkm_memory_size(disp->inst->memory);1467	ctrl->instMemAddrSpace = ADDR_FBMEM;1468	ctrl->instMemCpuCacheAttr = NV_MEMORY_WRITECOMBINED;1469 1470	ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl);1471	if (ret)1472		return ret;1473 1474	/* OBJs. */1475	ret = nvkm_gsp_client_device_ctor(gsp, &disp->rm.client, &disp->rm.device);1476	if (ret)1477		return ret;1478 1479	ret = nvkm_gsp_rm_alloc(&disp->rm.device.object, 0x00730000, NV04_DISPLAY_COMMON, 0,1480				&disp->rm.objcom);1481	if (ret)1482		return ret;1483 1484	{1485		NV2080_CTRL_INTERNAL_DISPLAY_GET_STATIC_INFO_PARAMS *ctrl;1486 1487		ctrl = nvkm_gsp_rm_ctrl_rd(&gsp->internal.device.subdevice,1488					   NV2080_CTRL_CMD_INTERNAL_DISPLAY_GET_STATIC_INFO,1489					   sizeof(*ctrl));1490		if (IS_ERR(ctrl))1491			return PTR_ERR(ctrl);1492 1493		disp->wndw.mask = ctrl->windowPresentMask;1494		disp->wndw.nr = fls(disp->wndw.mask);1495		nvkm_gsp_rm_ctrl_done(&gsp->internal.device.subdevice, ctrl);1496	}1497 1498	/* */1499	{1500#if defined(CONFIG_ACPI) && defined(CONFIG_X86)1501		NV2080_CTRL_INTERNAL_INIT_BRIGHTC_STATE_LOAD_PARAMS *ctrl;1502		struct nvkm_gsp_object *subdevice = &disp->rm.client.gsp->internal.device.subdevice;1503 1504		ctrl = nvkm_gsp_rm_ctrl_get(subdevice,1505					    NV2080_CTRL_CMD_INTERNAL_INIT_BRIGHTC_STATE_LOAD,1506					    sizeof(*ctrl));1507		if (IS_ERR(ctrl))1508			return PTR_ERR(ctrl);1509 1510		ctrl->status = 0x56; /* NV_ERR_NOT_SUPPORTED */1511 1512		{1513			const guid_t NBCI_DSM_GUID =1514				GUID_INIT(0xD4A50B75, 0x65C7, 0x46F7,1515					  0xBF, 0xB7, 0x41, 0x51, 0x4C, 0xEA, 0x02, 0x44);1516			u64 NBCI_DSM_REV = 0x00000102;1517			const guid_t NVHG_DSM_GUID =1518				GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,1519					  0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);1520			u64 NVHG_DSM_REV = 0x00000102;1521			acpi_handle handle = ACPI_HANDLE(device->dev);1522 1523			if (handle && acpi_has_method(handle, "_DSM")) {1524				bool nbci = acpi_check_dsm(handle, &NBCI_DSM_GUID, NBCI_DSM_REV,1525						           1ULL << 0x00000014);1526				bool nvhg = acpi_check_dsm(handle, &NVHG_DSM_GUID, NVHG_DSM_REV,1527						           1ULL << 0x00000014);1528 1529				if (nbci || nvhg) {1530					union acpi_object argv4 = {1531						.buffer.type    = ACPI_TYPE_BUFFER,1532						.buffer.length  = sizeof(ctrl->backLightData),1533						.buffer.pointer = kmalloc(argv4.buffer.length, GFP_KERNEL),1534					}, *obj;1535 1536					obj = acpi_evaluate_dsm(handle, nbci ? &NBCI_DSM_GUID : &NVHG_DSM_GUID,1537								0x00000102, 0x14, &argv4);1538					if (!obj) {1539						acpi_handle_info(handle, "failed to evaluate _DSM\n");1540					} else {1541						for (int i = 0; i < obj->package.count; i++) {1542							union acpi_object *elt = &obj->package.elements[i];1543							u32 size;1544 1545							if (elt->integer.value & ~0xffffffffULL)1546								size = 8;1547							else1548								size = 4;1549 1550							memcpy(&ctrl->backLightData[ctrl->backLightDataSize], &elt->integer.value, size);1551							ctrl->backLightDataSize += size;1552						}1553 1554						ctrl->status = 0;1555						ACPI_FREE(obj);1556					}1557 1558					kfree(argv4.buffer.pointer);1559				}1560			}1561		}1562 1563		ret = nvkm_gsp_rm_ctrl_wr(subdevice, ctrl);1564		if (ret)1565			return ret;1566#endif1567	}1568 1569	/* */1570	{1571		NV0073_CTRL_CMD_DP_SET_MANUAL_DISPLAYPORT_PARAMS *ctrl;1572 1573		ctrl = nvkm_gsp_rm_ctrl_get(&disp->rm.objcom,1574					    NV0073_CTRL_CMD_DP_SET_MANUAL_DISPLAYPORT,1575					    sizeof(*ctrl));1576		if (IS_ERR(ctrl))1577			return PTR_ERR(ctrl);1578 1579		ret = nvkm_gsp_rm_ctrl_wr(&disp->rm.objcom, ctrl);1580		if (ret)1581			return ret;1582	}1583 1584	/* */1585	{1586		NV0073_CTRL_SYSTEM_GET_NUM_HEADS_PARAMS *ctrl;1587 1588		ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,1589					   NV0073_CTRL_CMD_SYSTEM_GET_NUM_HEADS, sizeof(*ctrl));1590		if (IS_ERR(ctrl))1591			return PTR_ERR(ctrl);1592 1593		disp->head.nr = ctrl->numHeads;1594		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1595	}1596 1597	/* */1598	{1599		NV0073_CTRL_SPECIFIC_GET_ALL_HEAD_MASK_PARAMS *ctrl;1600 1601		ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,1602					   NV0073_CTRL_CMD_SPECIFIC_GET_ALL_HEAD_MASK,1603					   sizeof(*ctrl));1604		if (IS_ERR(ctrl))1605			return PTR_ERR(ctrl);1606 1607		disp->head.mask = ctrl->headMask;1608		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1609 1610		for_each_set_bit(i, &disp->head.mask, disp->head.nr) {1611			ret = nvkm_head_new_(&r535_head, disp, i);1612			if (ret)1613				return ret;1614		}1615	}1616 1617	disp->sor.nr = disp->func->sor.cnt(disp, &disp->sor.mask);1618	nvkm_debug(&disp->engine.subdev, "   SOR(s): %d (%02lx)\n", disp->sor.nr, disp->sor.mask);1619	for_each_set_bit(i, &disp->sor.mask, disp->sor.nr) {1620		ret = disp->func->sor.new(disp, i);1621		if (ret)1622			return ret;1623	}1624 1625	/* */1626	{1627		NV0073_CTRL_SYSTEM_GET_SUPPORTED_PARAMS *ctrl;1628		unsigned long mask;1629		int i;1630 1631		ctrl = nvkm_gsp_rm_ctrl_rd(&disp->rm.objcom,1632					   NV0073_CTRL_CMD_SYSTEM_GET_SUPPORTED, sizeof(*ctrl));1633		if (IS_ERR(ctrl))1634			return PTR_ERR(ctrl);1635 1636		mask = ctrl->displayMask;1637		nvkm_gsp_rm_ctrl_done(&disp->rm.objcom, ctrl);1638 1639		for_each_set_bit(i, &mask, 32) {1640			ret = r535_outp_new(disp, i);1641			if (ret)1642				return ret;1643		}1644	}1645 1646	ret = nvkm_event_init(&r535_disp_event, &gsp->subdev, 3, 32, &disp->rm.event);1647	if (WARN_ON(ret))1648		return ret;1649 1650	ret = nvkm_gsp_device_event_ctor(&disp->rm.device, 0x007e0000, NV2080_NOTIFIERS_HOTPLUG,1651					 r535_disp_hpd, &disp->rm.hpd);1652	if (ret)1653		return ret;1654 1655	ret = nvkm_gsp_device_event_ctor(&disp->rm.device, 0x007e0001, NV2080_NOTIFIERS_DP_IRQ,1656					 r535_disp_irq, &disp->rm.irq);1657	if (ret)1658		return ret;1659 1660	/* RAMHT. */1661	ret = nvkm_ramht_new(device, disp->func->ramht_size ? disp->func->ramht_size :1662			     0x1000, 0, disp->inst, &disp->ramht);1663	if (ret)1664		return ret;1665 1666	ret = nvkm_gsp_intr_stall(gsp, disp->engine.subdev.type, disp->engine.subdev.inst);1667	if (ret < 0)1668		return ret;1669 1670	ret = nvkm_inth_add(&device->vfn->intr, ret, NVKM_INTR_PRIO_NORMAL, &disp->engine.subdev,1671			    r535_disp_intr, &disp->engine.subdev.inth);1672	if (ret)1673		return ret;1674 1675	nvkm_inth_allow(&disp->engine.subdev.inth);1676	return 0;1677}1678 1679static void1680r535_disp_dtor(struct nvkm_disp *disp)1681{1682	kfree(disp->func);1683}1684 1685int1686r535_disp_new(const struct nvkm_disp_func *hw, struct nvkm_device *device,1687	      enum nvkm_subdev_type type, int inst, struct nvkm_disp **pdisp)1688{1689	struct nvkm_disp_func *rm;1690	int ret;1691 1692	if (!(rm = kzalloc(sizeof(*rm) + 6 * sizeof(rm->user[0]), GFP_KERNEL)))1693		return -ENOMEM;1694 1695	rm->dtor = r535_disp_dtor;1696	rm->oneinit = r535_disp_oneinit;1697	rm->init = r535_disp_init;1698	rm->fini = r535_disp_fini;1699	rm->uevent = hw->uevent;1700	rm->sor.cnt = r535_sor_cnt;1701	rm->sor.new = r535_sor_new;1702	rm->ramht_size = hw->ramht_size;1703 1704	rm->root = hw->root;1705 1706	for (int i = 0; hw->user[i].ctor; i++) {1707		switch (hw->user[i].base.oclass & 0xff) {1708		case 0x73: rm->user[i] = hw->user[i]; break;1709		case 0x7d: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_core; break;1710		case 0x7e: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_wndw; break;1711		case 0x7b: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_wimm; break;1712		case 0x7a: rm->user[i] = hw->user[i]; rm->user[i].chan = &r535_curs; break;1713		default:1714			WARN_ON(1);1715			continue;1716		}1717	}1718 1719	ret = nvkm_disp_new_(rm, device, type, inst, pdisp);1720	if (ret)1721		kfree(rm);1722 1723	mutex_init(&(*pdisp)->super.mutex); //XXX1724	return ret;1725}1726