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