diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c | 108 |
1 files changed, 97 insertions, 11 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c index f5f8dc8e8f35..e4ad1a6f6c88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c @@ -19,19 +19,96 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include "nv50.h" +#include "chan.h" +#include "priv.h" #include "head.h" #include "ior.h" -#include "channv50.h" -#include "rootnv50.h" #include <core/gpuobj.h> #include <subdev/timer.h> +#include <nvif/class.h> + +void +tu102_sor_dp_vcpi(struct nvkm_ior *sor, int head, u8 slot, u8 slot_nr, u16 pbn, u16 aligned) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 hoff = head * 0x800; + + nvkm_mask(device, 0x61657c + hoff, 0xffffffff, (aligned << 16) | pbn); + nvkm_mask(device, 0x616578 + hoff, 0x00003f3f, (slot_nr << 8) | slot); +} + +static int +tu102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + const u32 loff = nv50_sor_link(sor); + u32 dpctrl = 0x00000000; + u32 clksor = 0x00000000; + + clksor |= sor->dp.bw << 18; + dpctrl |= ((1 << sor->dp.nr) - 1) << 16; + if (sor->dp.mst) + dpctrl |= 0x40000000; + if (sor->dp.ef) + dpctrl |= 0x00004000; + + nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); + + /*XXX*/ + nvkm_msec(device, 40, NVKM_DELAY); + nvkm_mask(device, 0x612300 + soff, 0x00030000, 0x00010000); + nvkm_mask(device, 0x61c10c + loff, 0x00000003, 0x00000001); + + nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl); + return 0; +} + +static const struct nvkm_ior_func_dp +tu102_sor_dp = { + .lanes = { 0, 1, 2, 3 }, + .links = tu102_sor_dp_links, + .power = g94_sor_dp_power, + .pattern = gm107_sor_dp_pattern, + .drive = gm200_sor_dp_drive, + .vcpi = tu102_sor_dp_vcpi, + .audio = gv100_sor_dp_audio, + .audio_sym = gv100_sor_dp_audio_sym, + .watermark = gv100_sor_dp_watermark, +}; + +static const struct nvkm_ior_func +tu102_sor = { + .route = { + .get = gm200_sor_route_get, + .set = gm200_sor_route_set, + }, + .state = gv100_sor_state, + .power = nv50_sor_power, + .clock = gf119_sor_clock, + .hdmi = { + .ctrl = gv100_sor_hdmi_ctrl, + .scdc = gm200_sor_hdmi_scdc, + }, + .dp = &tu102_sor_dp, + .hda = &gv100_sor_hda, +}; + +static int +tu102_sor_new(struct nvkm_disp *disp, int id) +{ + struct nvkm_device *device = disp->engine.subdev.device; + u32 hda = nvkm_rd32(device, 0x08a15c); + + return nvkm_ior_new_(&tu102_sor, disp, SOR, id, hda & BIT(id)); +} + int -tu102_disp_init(struct nv50_disp *disp) +tu102_disp_init(struct nvkm_disp *disp) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = disp->engine.subdev.device; struct nvkm_head *head; int i, j; u32 tmp; @@ -58,7 +135,7 @@ tu102_disp_init(struct nv50_disp *disp) } /* Head capabilities. */ - list_for_each_entry(head, &disp->base.head, head) { + list_for_each_entry(head, &disp->heads, head) { const int id = head->id; /* RG. */ @@ -119,7 +196,7 @@ tu102_disp_init(struct nv50_disp *disp) nvkm_wr32(device, 0x611da4, 0x00000000); /* EN. */ /* HEAD_TIMING(n): VBLANK. */ - list_for_each_entry(head, &disp->base.head, head) { + list_for_each_entry(head, &disp->heads, head) { const u32 hoff = head->id * 4; nvkm_wr32(device, 0x611cc0 + hoff, 0x00000004); /* MSK. */ nvkm_wr32(device, 0x611d80 + hoff, 0x00000000); /* EN. */ @@ -131,23 +208,32 @@ tu102_disp_init(struct nv50_disp *disp) return 0; } -static const struct nv50_disp_func +static const struct nvkm_disp_func tu102_disp = { + .oneinit = nv50_disp_oneinit, .init = tu102_disp_init, .fini = gv100_disp_fini, .intr = gv100_disp_intr, - .uevent = &gv100_disp_chan_uevent, .super = gv100_disp_super, - .root = &tu102_disp_root_oclass, + .uevent = &gv100_disp_chan_uevent, .wndw = { .cnt = gv100_disp_wndw_cnt }, .head = { .cnt = gv100_head_cnt, .new = gv100_head_new }, .sor = { .cnt = gv100_sor_cnt, .new = tu102_sor_new }, .ramht_size = 0x2000, + .root = { 0, 0,TU102_DISP }, + .user = { + {{-1,-1,GV100_DISP_CAPS }, gv100_disp_caps_new }, + {{ 0, 0,TU102_DISP_CURSOR }, nvkm_disp_chan_new, &gv100_disp_curs }, + {{ 0, 0,TU102_DISP_WINDOW_IMM_CHANNEL_DMA}, nvkm_disp_wndw_new, &gv100_disp_wimm }, + {{ 0, 0,TU102_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gv100_disp_core }, + {{ 0, 0,TU102_DISP_WINDOW_CHANNEL_DMA }, nvkm_disp_wndw_new, &gv100_disp_wndw }, + {} + }, }; int tu102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_disp **pdisp) { - return nv50_disp_new_(&tu102_disp, device, type, inst, pdisp); + return nvkm_disp_new_(&tu102_disp, device, type, inst, pdisp); } |