Commit 2bc7ea71 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/nouveau-misc-2022-07-27' of git://anongit.freedesktop.org/drm/drm into drm-next

drm/nouveau-misc: display patches.

These are just some precursor and cleanup display patches from Ben,
tested by Lyude.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Dave Airlie <airlied@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CAPM=9ty0R37q0mohBr_CegpYLXK2=fAH54QfAsMhHfPygTsdQA@mail.gmail.com
parents ee8b1ef9 dfc4005f
...@@ -21,8 +21,7 @@ ...@@ -21,8 +21,7 @@
*/ */
#include "base.h" #include "base.h"
#include <nvif/cl507c.h> #include <nvif/if0014.h>
#include <nvif/event.h>
#include <nvif/push507c.h> #include <nvif/push507c.h>
#include <nvif/timer.h> #include <nvif/timer.h>
...@@ -306,8 +305,8 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 *format, ...@@ -306,8 +305,8 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 *format,
struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data, struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
struct nv50_wndw **pwndw) struct nv50_wndw **pwndw)
{ {
struct nv50_disp_base_channel_dma_v0 args = { struct nvif_disp_chan_v0 args = {
.head = head, .id = head,
}; };
struct nouveau_display *disp = nouveau_display(drm->dev); struct nouveau_display *disp = nouveau_display(drm->dev);
struct nv50_disp *disp50 = nv50_disp(drm->dev); struct nv50_disp *disp50 = nv50_disp(drm->dev);
...@@ -328,16 +327,6 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 *format, ...@@ -328,16 +327,6 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 *format,
return ret; return ret;
} }
ret = nvif_notify_ctor(&wndw->wndw.base.user, "kmsBaseNtfy",
wndw->notify.func, false,
NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT,
&(struct nvif_notify_uevent_req) {},
sizeof(struct nvif_notify_uevent_req),
sizeof(struct nvif_notify_uevent_rep),
&wndw->notify);
if (ret)
return ret;
wndw->ntfy = NV50_DISP_BASE_NTFY(wndw->id); wndw->ntfy = NV50_DISP_BASE_NTFY(wndw->id);
wndw->sema = NV50_DISP_BASE_SEM0(wndw->id); wndw->sema = NV50_DISP_BASE_SEM0(wndw->id);
wndw->data = 0x00000000; wndw->data = 0x00000000;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "core.h" #include "core.h"
#include "head.h" #include "head.h"
#include <nvif/cl507d.h> #include <nvif/if0014.h>
#include <nvif/push507c.h> #include <nvif/push507c.h>
#include <nvif/timer.h> #include <nvif/timer.h>
...@@ -157,7 +157,7 @@ int ...@@ -157,7 +157,7 @@ int
core507d_new_(const struct nv50_core_func *func, struct nouveau_drm *drm, core507d_new_(const struct nv50_core_func *func, struct nouveau_drm *drm,
s32 oclass, struct nv50_core **pcore) s32 oclass, struct nv50_core **pcore)
{ {
struct nv50_disp_core_channel_dma_v0 args = {}; struct nvif_disp_chan_v0 args = {};
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_core *core; struct nv50_core *core;
int ret; int ret;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "core.h" #include "core.h"
#include "head.h" #include "head.h"
#include <nvif/cl507a.h> #include <nvif/if0014.h>
#include <nvif/timer.h> #include <nvif/timer.h>
#include <nvhw/class/cl507a.h> #include <nvhw/class/cl507a.h>
...@@ -150,8 +150,8 @@ curs507a_new_(const struct nv50_wimm_func *func, struct nouveau_drm *drm, ...@@ -150,8 +150,8 @@ curs507a_new_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
int head, s32 oclass, u32 interlock_data, int head, s32 oclass, u32 interlock_data,
struct nv50_wndw **pwndw) struct nv50_wndw **pwndw)
{ {
struct nv50_disp_cursor_v0 args = { struct nvif_disp_chan_v0 args = {
.head = head, .id = head,
}; };
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_wndw *wndw; struct nv50_wndw *wndw;
......
...@@ -48,8 +48,8 @@ ...@@ -48,8 +48,8 @@
#include <nvif/class.h> #include <nvif/class.h>
#include <nvif/cl0002.h> #include <nvif/cl0002.h>
#include <nvif/cl5070.h> #include <nvif/cl5070.h>
#include <nvif/cl507d.h>
#include <nvif/event.h> #include <nvif/event.h>
#include <nvif/if0014.h>
#include <nvif/timer.h> #include <nvif/timer.h>
#include <nvhw/class/cl507c.h> #include <nvhw/class/cl507c.h>
...@@ -231,7 +231,7 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, ...@@ -231,7 +231,7 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
struct nv50_dmac *dmac) struct nv50_dmac *dmac)
{ {
struct nouveau_cli *cli = (void *)device->object.client; struct nouveau_cli *cli = (void *)device->object.client;
struct nv50_disp_core_channel_dma_v0 *args = data; struct nvif_disp_chan_v0 *args = data;
u8 type = NVIF_MEM_COHERENT; u8 type = NVIF_MEM_COHERENT;
int ret; int ret;
...@@ -529,24 +529,15 @@ static enum drm_connector_status ...@@ -529,24 +529,15 @@ static enum drm_connector_status
nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev); u32 loadval;
struct {
struct nv50_disp_mthd_v1 base;
struct nv50_disp_dac_load_v0 load;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_DAC_LOAD,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = nv_encoder->dcb->hashm,
};
int ret; int ret;
args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval; loadval = nouveau_drm(encoder->dev)->vbios.dactestval;
if (args.load.data == 0) if (loadval == 0)
args.load.data = 340; loadval = 340;
ret = nvif_mthd(&disp->disp->object, 0, &args, sizeof(args)); ret = nvif_outp_load_detect(&nv_encoder->outp, loadval);
if (ret || !args.load.load) if (ret <= 0)
return connector_status_disconnected; return connector_status_disconnected;
return connector_status_connected; return connector_status_connected;
...@@ -563,6 +554,10 @@ nv50_dac_help = { ...@@ -563,6 +554,10 @@ nv50_dac_help = {
static void static void
nv50_dac_destroy(struct drm_encoder *encoder) nv50_dac_destroy(struct drm_encoder *encoder)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
nvif_outp_dtor(&nv_encoder->outp);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(encoder); kfree(encoder);
} }
...@@ -576,6 +571,7 @@ static int ...@@ -576,6 +571,7 @@ static int
nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
{ {
struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nouveau_drm *drm = nouveau_drm(connector->dev);
struct nv50_disp *disp = nv50_disp(connector->dev);
struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device); struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device);
struct nvkm_i2c_bus *bus; struct nvkm_i2c_bus *bus;
struct nouveau_encoder *nv_encoder; struct nouveau_encoder *nv_encoder;
...@@ -599,7 +595,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) ...@@ -599,7 +595,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
drm_encoder_helper_add(encoder, &nv50_dac_help); drm_encoder_helper_add(encoder, &nv50_dac_help);
drm_connector_attach_encoder(connector, encoder); drm_connector_attach_encoder(connector, encoder);
return 0; return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp);
} }
/* /*
...@@ -1822,6 +1818,9 @@ static void ...@@ -1822,6 +1818,9 @@ static void
nv50_sor_destroy(struct drm_encoder *encoder) nv50_sor_destroy(struct drm_encoder *encoder)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
nvif_outp_dtor(&nv_encoder->outp);
nv50_mstm_del(&nv_encoder->dp.mstm); nv50_mstm_del(&nv_encoder->dp.mstm);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
...@@ -1918,7 +1917,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) ...@@ -1918,7 +1917,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
nv_encoder->i2c = &bus->i2c; nv_encoder->i2c = &bus->i2c;
} }
return 0; return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp);
} }
/****************************************************************************** /******************************************************************************
...@@ -1999,6 +1998,10 @@ nv50_pior_help = { ...@@ -1999,6 +1998,10 @@ nv50_pior_help = {
static void static void
nv50_pior_destroy(struct drm_encoder *encoder) nv50_pior_destroy(struct drm_encoder *encoder)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
nvif_outp_dtor(&nv_encoder->outp);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(encoder); kfree(encoder);
} }
...@@ -2056,7 +2059,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) ...@@ -2056,7 +2059,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1); disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1);
nv50_outp_dump_caps(drm, nv_encoder); nv50_outp_dump_caps(drm, nv_encoder);
return 0; return nvif_outp_ctor(disp->disp, nv_encoder->base.base.name, dcbe->id, &nv_encoder->outp);
} }
/****************************************************************************** /******************************************************************************
......
...@@ -21,14 +21,14 @@ ...@@ -21,14 +21,14 @@
*/ */
#include "oimm.h" #include "oimm.h"
#include <nvif/cl507b.h> #include <nvif/if0014.h>
static int static int
oimm507b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm, oimm507b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
s32 oclass, struct nv50_wndw *wndw) s32 oclass, struct nv50_wndw *wndw)
{ {
struct nv50_disp_overlay_v0 args = { struct nvif_disp_chan_v0 args = {
.head = wndw->id, .id = wndw->id,
}; };
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
int ret; int ret;
......
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <nvif/cl507e.h> #include <nvif/if0014.h>
#include <nvif/event.h>
#include <nvif/push507c.h> #include <nvif/push507c.h>
#include <nvhw/class/cl507e.h> #include <nvhw/class/cl507e.h>
...@@ -147,8 +146,8 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format, ...@@ -147,8 +146,8 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data, struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
struct nv50_wndw **pwndw) struct nv50_wndw **pwndw)
{ {
struct nv50_disp_overlay_channel_dma_v0 args = { struct nvif_disp_chan_v0 args = {
.head = head, .id = head,
}; };
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_wndw *wndw; struct nv50_wndw *wndw;
...@@ -169,16 +168,6 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format, ...@@ -169,16 +168,6 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
return ret; return ret;
} }
ret = nvif_notify_ctor(&wndw->wndw.base.user, "kmsOvlyNtfy",
wndw->notify.func, false,
NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT,
&(struct nvif_notify_uevent_req) {},
sizeof(struct nvif_notify_uevent_req),
sizeof(struct nvif_notify_uevent_rep),
&wndw->notify);
if (ret)
return ret;
wndw->ntfy = NV50_DISP_OVLY_NTFY(wndw->id); wndw->ntfy = NV50_DISP_OVLY_NTFY(wndw->id);
wndw->sema = NV50_DISP_OVLY_SEM0(wndw->id); wndw->sema = NV50_DISP_OVLY_SEM0(wndw->id);
wndw->data = 0x00000000; wndw->data = 0x00000000;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "atom.h" #include "atom.h"
#include "wndw.h" #include "wndw.h"
#include <nvif/clc37b.h> #include <nvif/if0014.h>
#include <nvif/pushc37b.h> #include <nvif/pushc37b.h>
#include <nvhw/class/clc37b.h> #include <nvhw/class/clc37b.h>
...@@ -68,9 +68,8 @@ static int ...@@ -68,9 +68,8 @@ static int
wimmc37b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm, wimmc37b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
s32 oclass, struct nv50_wndw *wndw) s32 oclass, struct nv50_wndw *wndw)
{ {
struct nvc37b_window_imm_channel_dma_v0 args = { struct nvif_disp_chan_v0 args = {
.pushbuf = 0xb0007b00 | wndw->id, .id = wndw->id,
.index = wndw->id,
}; };
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
int ret; int ret;
......
...@@ -644,7 +644,6 @@ nv50_wndw_destroy(struct drm_plane *plane) ...@@ -644,7 +644,6 @@ nv50_wndw_destroy(struct drm_plane *plane)
nv50_wndw_ctxdma_del(ctxdma); nv50_wndw_ctxdma_del(ctxdma);
} }
nvif_notify_dtor(&wndw->notify);
nv50_dmac_destroy(&wndw->wimm); nv50_dmac_destroy(&wndw->wimm);
nv50_dmac_destroy(&wndw->wndw); nv50_dmac_destroy(&wndw->wndw);
...@@ -688,12 +687,6 @@ nv50_wndw = { ...@@ -688,12 +687,6 @@ nv50_wndw = {
.format_mod_supported = nv50_plane_format_mod_supported, .format_mod_supported = nv50_plane_format_mod_supported,
}; };
static int
nv50_wndw_notify(struct nvif_notify *notify)
{
return NVIF_NOTIFY_KEEP;
}
static const u64 nv50_cursor_format_modifiers[] = { static const u64 nv50_cursor_format_modifiers[] = {
DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID, DRM_FORMAT_MOD_INVALID,
...@@ -747,8 +740,6 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev, ...@@ -747,8 +740,6 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
return ret; return ret;
} }
wndw->notify.func = nv50_wndw_notify;
if (wndw->func->blend_set) { if (wndw->func->blend_set) {
ret = drm_plane_create_zpos_property(&wndw->plane, ret = drm_plane_create_zpos_property(&wndw->plane,
nv50_wndw_zpos_default(&wndw->plane), 0, 254); nv50_wndw_zpos_default(&wndw->plane), 0, 254);
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#include "atom.h" #include "atom.h"
#include "lut.h" #include "lut.h"
#include <nvif/notify.h>
struct nv50_wndw_ctxdma { struct nv50_wndw_ctxdma {
struct list_head head; struct list_head head;
struct nvif_object object; struct nvif_object object;
...@@ -30,7 +28,6 @@ struct nv50_wndw { ...@@ -30,7 +28,6 @@ struct nv50_wndw {
struct nv50_dmac wndw; struct nv50_dmac wndw;
struct nv50_dmac wimm; struct nv50_dmac wimm;
struct nvif_notify notify;
u16 ntfy; u16 ntfy;
u16 sema; u16 sema;
u32 data; u32 data;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <nouveau_bo.h> #include <nouveau_bo.h>
#include <nvif/clc37e.h> #include <nvif/if0014.h>
#include <nvif/pushc37b.h> #include <nvif/pushc37b.h>
#include <nvhw/class/clc37e.h> #include <nvhw/class/clc37e.h>
...@@ -351,9 +351,8 @@ wndwc37e_new_(const struct nv50_wndw_func *func, struct nouveau_drm *drm, ...@@ -351,9 +351,8 @@ wndwc37e_new_(const struct nv50_wndw_func *func, struct nouveau_drm *drm,
enum drm_plane_type type, int index, s32 oclass, u32 heads, enum drm_plane_type type, int index, s32 oclass, u32 heads,
struct nv50_wndw **pwndw) struct nv50_wndw **pwndw)
{ {
struct nvc37e_window_channel_dma_v0 args = { struct nvif_disp_chan_v0 args = {
.pushbuf = 0xb0007e00 | index, .id = index,
.index = index,
}; };
struct nv50_disp *disp = nv50_disp(drm->dev); struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_wndw *wndw; struct nv50_wndw *wndw;
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <nouveau_bo.h> #include <nouveau_bo.h>
#include <nvif/clc37e.h>
#include <nvif/pushc37b.h> #include <nvif/pushc37b.h>
#include <nvhw/class/clc57e.h> #include <nvhw/class/clc57e.h>
......
...@@ -30,7 +30,6 @@ struct nv50_disp_mthd_v1 { ...@@ -30,7 +30,6 @@ struct nv50_disp_mthd_v1 {
__u8 version; __u8 version;
#define NV50_DISP_MTHD_V1_ACQUIRE 0x01 #define NV50_DISP_MTHD_V1_ACQUIRE 0x01
#define NV50_DISP_MTHD_V1_RELEASE 0x02 #define NV50_DISP_MTHD_V1_RELEASE 0x02
#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11
#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21 #define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22 #define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23 #define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
...@@ -50,13 +49,6 @@ struct nv50_disp_acquire_v0 { ...@@ -50,13 +49,6 @@ struct nv50_disp_acquire_v0 {
__u8 pad04[4]; __u8 pad04[4];
}; };
struct nv50_disp_dac_load_v0 {
__u8 version;
__u8 load;
__u8 pad02[2];
__u32 data;
};
struct nv50_disp_sor_hda_eld_v0 { struct nv50_disp_sor_hda_eld_v0 {
__u8 version; __u8 version;
__u8 pad01[7]; __u8 pad01[7];
......
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL507A_H__
#define __NVIF_CL507A_H__
struct nv50_disp_cursor_v0 {
__u8 version;
__u8 head;
__u8 pad02[6];
};
#define NV50_DISP_CURSOR_V0_NTFY_UEVENT 0x00
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL507B_H__
#define __NVIF_CL507B_H__
struct nv50_disp_overlay_v0 {
__u8 version;
__u8 head;
__u8 pad02[6];
};
#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT 0x00
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL507C_H__
#define __NVIF_CL507C_H__
struct nv50_disp_base_channel_dma_v0 {
__u8 version;
__u8 head;
__u8 pad02[6];
__u64 pushbuf;
};
#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL507D_H__
#define __NVIF_CL507D_H__
struct nv50_disp_core_channel_dma_v0 {
__u8 version;
__u8 pad01[7];
__u64 pushbuf;
};
#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CL507E_H__
#define __NVIF_CL507E_H__
struct nv50_disp_overlay_channel_dma_v0 {
__u8 version;
__u8 head;
__u8 pad02[6];
__u64 pushbuf;
};
#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CLC37B_H__
#define __NVIF_CLC37B_H__
struct nvc37b_window_imm_channel_dma_v0 {
__u8 version;
__u8 index;
__u8 pad02[6];
__u64 pushbuf;
};
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CLC37E_H__
#define __NVIF_CLC37E_H__
struct nvc37e_window_channel_dma_v0 {
__u8 version;
__u8 index;
__u8 pad02[6];
__u64 pushbuf;
};
#define NVC37E_WINDOW_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_CONN_H__
#define __NVIF_CONN_H__
#include <nvif/object.h>
struct nvif_disp;
struct nvif_conn {
struct nvif_object object;
};
int nvif_conn_ctor(struct nvif_disp *, const char *name, int id, struct nvif_conn *);
void nvif_conn_dtor(struct nvif_conn *);
#define NVIF_CONN_HPD_STATUS_UNSUPPORTED 0 /* negative if query fails */
#define NVIF_CONN_HPD_STATUS_NOT_PRESENT 1
#define NVIF_CONN_HPD_STATUS_PRESENT 2
int nvif_conn_hpd_status(struct nvif_conn *);
#endif
...@@ -5,6 +5,8 @@ struct nvif_device; ...@@ -5,6 +5,8 @@ struct nvif_device;
struct nvif_disp { struct nvif_disp {
struct nvif_object object; struct nvif_object object;
unsigned long conn_mask;
unsigned long outp_mask;
}; };
int nvif_disp_ctor(struct nvif_device *, const char *name, s32 oclass, int nvif_disp_ctor(struct nvif_device *, const char *name, s32 oclass,
......
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF0010_H__
#define __NVIF_IF0010_H__
union nvif_disp_args {
struct nvif_disp_v0 {
__u8 version;
__u8 pad01[3];
__u32 conn_mask;
__u32 outp_mask;
} v0;
};
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF0011_H__
#define __NVIF_IF0011_H__
union nvif_conn_args {
struct nvif_conn_v0 {
__u8 version;
__u8 id; /* DCB connector table index. */
__u8 pad02[6];
} v0;
};
#define NVIF_CONN_V0_HPD_STATUS 0x00000000
union nvif_conn_hpd_status_args {
struct nvif_conn_hpd_status_v0 {
__u8 version;
__u8 support;
__u8 present;
__u8 pad03[5];
} v0;
};
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF0012_H__
#define __NVIF_IF0012_H__
union nvif_outp_args {
struct nvif_outp_v0 {
__u8 version;
__u8 id; /* DCB device index. */
__u8 pad02[6];
} v0;
};
#define NVIF_OUTP_V0_LOAD_DETECT 0x00
union nvif_outp_load_detect_args {
struct nvif_outp_load_detect_v0 {
__u8 version;
__u8 load;
__u8 pad02[2];
__u32 data; /*TODO: move vbios loadval parsing into nvkm */
} v0;
};
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_IF0014_H__
#define __NVIF_IF0014_H__
union nvif_disp_chan_args {
struct nvif_disp_chan_v0 {
__u8 version;
__u8 id;
__u8 pad02[6];
__u64 pushbuf;
} v0;
};
#endif
/* SPDX-License-Identifier: MIT */
#ifndef __NVIF_OUTP_H__
#define __NVIF_OUTP_H__
#include <nvif/object.h>
struct nvif_disp;
struct nvif_outp {
struct nvif_object object;
};
int nvif_outp_ctor(struct nvif_disp *, const char *name, int id, struct nvif_outp *);
void nvif_outp_dtor(struct nvif_outp *);
int nvif_outp_load_detect(struct nvif_outp *, u32 loadval);
#endif
...@@ -17,4 +17,13 @@ ...@@ -17,4 +17,13 @@
#endif #endif
#define NVIF_ERROR(o,f,a...) NVIF_PRINT(errorf, (o), f, ##a) #define NVIF_ERROR(o,f,a...) NVIF_PRINT(errorf, (o), f, ##a)
#define NVIF_ERRON(c,o,f,a...) do { \
struct nvif_object *_object = (o); \
int _cond = (c); \
if (_cond) { \
NVIF_ERROR(_object, f" (ret:%d)", ##a, _cond); \
} else { \
NVIF_DEBUG(_object, f, ##a); \
} \
} while(0)
#endif #endif
...@@ -3,23 +3,56 @@ ...@@ -3,23 +3,56 @@
#define __NVKM_DISP_H__ #define __NVKM_DISP_H__
#define nvkm_disp(p) container_of((p), struct nvkm_disp, engine) #define nvkm_disp(p) container_of((p), struct nvkm_disp, engine)
#include <core/engine.h> #include <core/engine.h>
#include <core/object.h>
#include <core/event.h> #include <core/event.h>
struct nvkm_disp { struct nvkm_disp {
const struct nvkm_disp_func *func; const struct nvkm_disp_func *func;
struct nvkm_engine engine; struct nvkm_engine engine;
struct list_head head; struct list_head heads;
struct list_head ior; struct list_head iors;
struct list_head outp; struct list_head outps;
struct list_head conn; struct list_head conns;
struct nvkm_event hpd; struct nvkm_event hpd;
struct nvkm_event vblank; struct nvkm_event vblank;
struct {
struct workqueue_struct *wq;
struct work_struct work;
u32 pending;
struct mutex mutex;
} super;
#define NVKM_DISP_EVENT_CHAN_AWAKEN BIT(0)
struct nvkm_event uevent;
struct {
unsigned long mask;
int nr;
} wndw, head, dac;
struct {
unsigned long mask;
int nr;
u32 lvdsconf;
} sor;
struct {
unsigned long mask;
int nr;
u8 type[3];
} pior;
struct nvkm_gpuobj *inst;
struct nvkm_ramht *ramht;
struct nvkm_disp_chan *chan[81];
struct { struct {
spinlock_t lock; spinlock_t lock;
struct nvkm_oproxy *object; struct nvkm_object object;
} client; } client;
}; };
......
...@@ -54,6 +54,7 @@ struct dcb_output { ...@@ -54,6 +54,7 @@ struct dcb_output {
} tmdsconf; } tmdsconf;
}; };
bool i2c_upper_default; bool i2c_upper_default;
int id;
}; };
u16 dcb_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len); u16 dcb_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
......
...@@ -1801,6 +1801,8 @@ parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp) ...@@ -1801,6 +1801,8 @@ parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp)
ret = parse_dcb20_entry(dev, dcb, conn, conf, entry); ret = parse_dcb20_entry(dev, dcb, conn, conf, entry);
else else
ret = parse_dcb15_entry(dev, dcb, conn, conf, entry); ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
entry->id = idx;
if (!ret) if (!ret)
return 1; /* stop parsing */ return 1; /* stop parsing */
......
...@@ -404,6 +404,7 @@ nouveau_connector_destroy(struct drm_connector *connector) ...@@ -404,6 +404,7 @@ nouveau_connector_destroy(struct drm_connector *connector)
drm_dp_cec_unregister_connector(&nv_connector->aux); drm_dp_cec_unregister_connector(&nv_connector->aux);
kfree(nv_connector->aux.name); kfree(nv_connector->aux.name);
} }
nvif_conn_dtor(&nv_connector->conn);
kfree(connector); kfree(connector);
} }
...@@ -1386,6 +1387,15 @@ nouveau_connector_create(struct drm_device *dev, ...@@ -1386,6 +1387,15 @@ nouveau_connector_create(struct drm_device *dev,
drm_connector_init(dev, connector, funcs, type); drm_connector_init(dev, connector, funcs, type);
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
if (nv_connector->dcb && (disp->disp.conn_mask & BIT(nv_connector->index))) {
ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index,
&nv_connector->conn);
if (ret) {
kfree(nv_connector);
return ERR_PTR(ret);
}
}
connector->funcs->reset(connector); connector->funcs->reset(connector);
nouveau_conn_attach_properties(connector); nouveau_conn_attach_properties(connector);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#ifndef __NOUVEAU_CONNECTOR_H__ #ifndef __NOUVEAU_CONNECTOR_H__
#define __NOUVEAU_CONNECTOR_H__ #define __NOUVEAU_CONNECTOR_H__
#include <nvif/conn.h>
#include <nvif/notify.h> #include <nvif/notify.h>
#include <nvhw/class/cl507d.h> #include <nvhw/class/cl507d.h>
...@@ -123,6 +123,7 @@ struct nouveau_connector { ...@@ -123,6 +123,7 @@ struct nouveau_connector {
u8 index; u8 index;
u8 *dcb; u8 *dcb;
struct nvif_conn conn;
struct nvif_notify hpd; struct nvif_notify hpd;
struct drm_dp_aux aux; struct drm_dp_aux aux;
......
...@@ -107,7 +107,7 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, ...@@ -107,7 +107,7 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
struct nv50_mstm *mstm = nv_encoder->dp.mstm; struct nv50_mstm *mstm = nv_encoder->dp.mstm;
enum drm_connector_status status; enum drm_connector_status status;
u8 *dpcd = nv_encoder->dp.dpcd; u8 *dpcd = nv_encoder->dp.dpcd;
int ret = NOUVEAU_DP_NONE; int ret = NOUVEAU_DP_NONE, hpd;
/* If we've already read the DPCD on an eDP device, we don't need to /* If we've already read the DPCD on an eDP device, we don't need to
* reread it as it won't change * reread it as it won't change
...@@ -133,6 +133,16 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, ...@@ -133,6 +133,16 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
} }
} }
/* Check status of HPD pin before attempting an AUX transaction that
* would result in a number of (futile) retries on a connector which
* has no display plugged.
*
* TODO: look into checking this before probing I2C to detect DVI/HDMI
*/
hpd = nvif_conn_hpd_status(&nv_connector->conn);
if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT)
goto out;
status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder); status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder);
if (status == connector_status_disconnected) if (status == connector_status_disconnected)
goto out; goto out;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#ifndef __NOUVEAU_ENCODER_H__ #ifndef __NOUVEAU_ENCODER_H__
#define __NOUVEAU_ENCODER_H__ #define __NOUVEAU_ENCODER_H__
#include <nvif/outp.h>
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
#include <drm/display/drm_dp_helper.h> #include <drm/display/drm_dp_helper.h>
...@@ -46,6 +46,7 @@ struct nouveau_encoder { ...@@ -46,6 +46,7 @@ struct nouveau_encoder {
struct drm_encoder_slave base; struct drm_encoder_slave base;
struct dcb_output *dcb; struct dcb_output *dcb;
struct nvif_outp outp;
int or; int or;
int link; int link;
......
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
nvif-y := nvif/object.o nvif-y := nvif/object.o
nvif-y += nvif/client.o nvif-y += nvif/client.o
nvif-y += nvif/conn.o
nvif-y += nvif/device.o nvif-y += nvif/device.o
nvif-y += nvif/disp.o nvif-y += nvif/disp.o
nvif-y += nvif/driver.o nvif-y += nvif/driver.o
...@@ -8,6 +9,7 @@ nvif-y += nvif/fifo.o ...@@ -8,6 +9,7 @@ nvif-y += nvif/fifo.o
nvif-y += nvif/mem.o nvif-y += nvif/mem.o
nvif-y += nvif/mmu.o nvif-y += nvif/mmu.o
nvif-y += nvif/notify.o nvif-y += nvif/notify.o
nvif-y += nvif/outp.o
nvif-y += nvif/timer.o nvif-y += nvif/timer.o
nvif-y += nvif/vmm.o nvif-y += nvif/vmm.o
......
...@@ -19,34 +19,44 @@ ...@@ -19,34 +19,44 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "rootnv50.h" #include <nvif/conn.h>
#include "channv50.h" #include <nvif/disp.h>
#include <nvif/printf.h>
#include <nvif/class.h> #include <nvif/class.h>
#include <nvif/if0011.h>
static const struct nv50_disp_root_func int
ga102_disp_root = { nvif_conn_hpd_status(struct nvif_conn *conn)
.user = {
{{-1,-1,GV100_DISP_CAPS }, gv100_disp_caps_new },
{{0,0,GA102_DISP_CURSOR }, gv100_disp_curs_new },
{{0,0,GA102_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
{{0,0,GA102_DISP_CORE_CHANNEL_DMA }, gv100_disp_core_new },
{{0,0,GA102_DISP_WINDOW_CHANNEL_DMA }, gv100_disp_wndw_new },
{}
},
};
static int
ga102_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
void *data, u32 size, struct nvkm_object **pobject)
{ {
return nv50_disp_root_new_(&ga102_disp_root, disp, oclass, data, size, pobject); struct nvif_conn_hpd_status_v0 args;
int ret;
args.version = 0;
ret = nvif_mthd(&conn->object, NVIF_CONN_V0_HPD_STATUS, &args, sizeof(args));
NVIF_ERRON(ret, &conn->object, "[HPD_STATUS] support:%d present:%d",
args.support, args.present);
return ret ? ret : !!args.support + !!args.present;
}
void
nvif_conn_dtor(struct nvif_conn *conn)
{
nvif_object_dtor(&conn->object);
} }
const struct nvkm_disp_oclass int
ga102_disp_root_oclass = { nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_conn *conn)
.base.oclass = GA102_DISP, {
.base.minver = -1, struct nvif_conn_v0 args;
.base.maxver = -1, int ret;
.ctor = ga102_disp_root_new,
}; args.version = 0;
args.id = id;
ret = nvif_object_ctor(&disp->object, name ?: "nvifConn", id, NVIF_CLASS_CONN,
&args, sizeof(args), &conn->object);
NVIF_ERRON(ret, &disp->object, "[NEW conn id:%d]", id);
return ret;
}
...@@ -21,8 +21,10 @@ ...@@ -21,8 +21,10 @@
*/ */
#include <nvif/disp.h> #include <nvif/disp.h>
#include <nvif/device.h> #include <nvif/device.h>
#include <nvif/printf.h>
#include <nvif/class.h> #include <nvif/class.h>
#include <nvif/if0010.h>
void void
nvif_disp_dtor(struct nvif_disp *disp) nvif_disp_dtor(struct nvif_disp *disp)
...@@ -31,33 +33,48 @@ nvif_disp_dtor(struct nvif_disp *disp) ...@@ -31,33 +33,48 @@ nvif_disp_dtor(struct nvif_disp *disp)
} }
int int
nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct nvif_disp *disp)
struct nvif_disp *disp)
{ {
static const struct nvif_mclass disps[] = { static const struct nvif_mclass disps[] = {
{ GA102_DISP, -1 }, { GA102_DISP, 0 },
{ TU102_DISP, -1 }, { TU102_DISP, 0 },
{ GV100_DISP, -1 }, { GV100_DISP, 0 },
{ GP102_DISP, -1 }, { GP102_DISP, 0 },
{ GP100_DISP, -1 }, { GP100_DISP, 0 },
{ GM200_DISP, -1 }, { GM200_DISP, 0 },
{ GM107_DISP, -1 }, { GM107_DISP, 0 },
{ GK110_DISP, -1 }, { GK110_DISP, 0 },
{ GK104_DISP, -1 }, { GK104_DISP, 0 },
{ GF110_DISP, -1 }, { GF110_DISP, 0 },
{ GT214_DISP, -1 }, { GT214_DISP, 0 },
{ GT206_DISP, -1 }, { GT206_DISP, 0 },
{ GT200_DISP, -1 }, { GT200_DISP, 0 },
{ G82_DISP, -1 }, { G82_DISP, 0 },
{ NV50_DISP, -1 }, { NV50_DISP, 0 },
{ NV04_DISP, -1 }, { NV04_DISP, 0 },
{} {}
}; };
int cid = nvif_sclass(&device->object, disps, oclass); struct nvif_disp_v0 args;
int cid, ret;
cid = nvif_sclass(&device->object, disps, oclass);
disp->object.client = NULL; disp->object.client = NULL;
if (cid < 0) if (cid < 0) {
NVIF_ERRON(cid, &device->object, "[NEW disp%04x] not supported", oclass);
return cid; return cid;
}
args.version = 0;
ret = nvif_object_ctor(&device->object, name ?: "nvifDisp", 0,
disps[cid].oclass, &args, sizeof(args), &disp->object);
NVIF_ERRON(ret, &device->object, "[NEW disp%04x]", disps[cid].oclass);
if (ret)
return ret;
return nvif_object_ctor(&device->object, name ? name : "nvifDisp", 0, NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x",
disps[cid].oclass, NULL, 0, &disp->object); args.conn_mask, args.outp_mask);
disp->conn_mask = args.conn_mask;
disp->outp_mask = args.outp_mask;
return 0;
} }
/* /*
* Copyright 2012 Red Hat Inc. * Copyright 2021 Red Hat Inc.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
...@@ -18,38 +18,45 @@ ...@@ -18,38 +18,45 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/ */
#include "rootnv50.h" #include <nvif/outp.h>
#include "channv50.h" #include <nvif/disp.h>
#include <nvif/printf.h>
#include <nvif/class.h> #include <nvif/class.h>
#include <nvif/if0012.h>
int
nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval)
{
struct nvif_outp_load_detect_v0 args;
int ret;
args.version = 0;
args.data = loadval;
ret = nvif_mthd(&outp->object, NVIF_OUTP_V0_LOAD_DETECT, &args, sizeof(args));
NVIF_ERRON(ret, &outp->object, "[LOAD_DETECT data:%08x] load:%02x", args.data, args.load);
return ret < 0 ? ret : args.load;
}
static const struct nv50_disp_root_func void
g94_disp_root = { nvif_outp_dtor(struct nvif_outp *outp)
.user = {
{{0,0, G82_DISP_CURSOR }, nv50_disp_curs_new },
{{0,0, G82_DISP_OVERLAY }, nv50_disp_oimm_new },
{{0,0,GT200_DISP_BASE_CHANNEL_DMA }, g84_disp_base_new },
{{0,0,GT206_DISP_CORE_CHANNEL_DMA }, g94_disp_core_new },
{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, gt200_disp_ovly_new },
{}
},
};
static int
g94_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
void *data, u32 size, struct nvkm_object **pobject)
{ {
return nv50_disp_root_new_(&g94_disp_root, disp, oclass, nvif_object_dtor(&outp->object);
data, size, pobject);
} }
const struct nvkm_disp_oclass int
g94_disp_root_oclass = { nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_outp *outp)
.base.oclass = GT206_DISP, {
.base.minver = -1, struct nvif_outp_v0 args;
.base.maxver = -1, int ret;
.ctor = g94_disp_root_new,
}; args.version = 0;
args.id = id;
ret = nvif_object_ctor(&disp->object, name ?: "nvifOutp", id, NVIF_CLASS_OUTP,
&args, sizeof(args), &outp->object);
NVIF_ERRON(ret, &disp->object, "[NEW outp id:%d]", id);
return ret;
}
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
nvkm-y += nvkm/engine/disp/base.o nvkm-y += nvkm/engine/disp/base.o
nvkm-y += nvkm/engine/disp/chan.o
nvkm-y += nvkm/engine/disp/conn.o
nvkm-y += nvkm/engine/disp/dp.o
nvkm-y += nvkm/engine/disp/hdmi.o
nvkm-y += nvkm/engine/disp/head.o
nvkm-y += nvkm/engine/disp/ior.o
nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/vga.o
nvkm-y += nvkm/engine/disp/nv04.o nvkm-y += nvkm/engine/disp/nv04.o
nvkm-y += nvkm/engine/disp/nv50.o nvkm-y += nvkm/engine/disp/nv50.o
nvkm-y += nvkm/engine/disp/g84.o nvkm-y += nvkm/engine/disp/g84.o
...@@ -18,110 +27,10 @@ nvkm-y += nvkm/engine/disp/gp102.o ...@@ -18,110 +27,10 @@ nvkm-y += nvkm/engine/disp/gp102.o
nvkm-y += nvkm/engine/disp/gv100.o nvkm-y += nvkm/engine/disp/gv100.o
nvkm-y += nvkm/engine/disp/tu102.o nvkm-y += nvkm/engine/disp/tu102.o
nvkm-y += nvkm/engine/disp/ga102.o nvkm-y += nvkm/engine/disp/ga102.o
nvkm-y += nvkm/engine/disp/vga.o
nvkm-y += nvkm/engine/disp/head.o
nvkm-y += nvkm/engine/disp/headnv04.o
nvkm-y += nvkm/engine/disp/headnv50.o
nvkm-y += nvkm/engine/disp/headgf119.o
nvkm-y += nvkm/engine/disp/headgv100.o
nvkm-y += nvkm/engine/disp/ior.o
nvkm-y += nvkm/engine/disp/dacnv50.o
nvkm-y += nvkm/engine/disp/dacgf119.o
nvkm-y += nvkm/engine/disp/piornv50.o
nvkm-y += nvkm/engine/disp/sornv50.o
nvkm-y += nvkm/engine/disp/sorg84.o
nvkm-y += nvkm/engine/disp/sorg94.o
nvkm-y += nvkm/engine/disp/sormcp77.o
nvkm-y += nvkm/engine/disp/sorgt215.o
nvkm-y += nvkm/engine/disp/sormcp89.o
nvkm-y += nvkm/engine/disp/sorgf119.o
nvkm-y += nvkm/engine/disp/sorgk104.o
nvkm-y += nvkm/engine/disp/sorgm107.o
nvkm-y += nvkm/engine/disp/sorgm200.o
nvkm-y += nvkm/engine/disp/sorgp100.o
nvkm-y += nvkm/engine/disp/sorgv100.o
nvkm-y += nvkm/engine/disp/sortu102.o
nvkm-y += nvkm/engine/disp/sorga102.o
nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/dp.o
nvkm-y += nvkm/engine/disp/hdagt215.o
nvkm-y += nvkm/engine/disp/hdagf119.o
nvkm-y += nvkm/engine/disp/hdagv100.o
nvkm-y += nvkm/engine/disp/hdmi.o
nvkm-y += nvkm/engine/disp/hdmig84.o
nvkm-y += nvkm/engine/disp/hdmigt215.o
nvkm-y += nvkm/engine/disp/hdmigf119.o
nvkm-y += nvkm/engine/disp/hdmigk104.o
nvkm-y += nvkm/engine/disp/hdmigm200.o
nvkm-y += nvkm/engine/disp/hdmigv100.o
nvkm-y += nvkm/engine/disp/conn.o
nvkm-y += nvkm/engine/disp/rootnv04.o nvkm-y += nvkm/engine/disp/rootnv04.o
nvkm-y += nvkm/engine/disp/rootnv50.o nvkm-y += nvkm/engine/disp/rootnv50.o
nvkm-y += nvkm/engine/disp/rootg84.o
nvkm-y += nvkm/engine/disp/rootg94.o
nvkm-y += nvkm/engine/disp/rootgt200.o
nvkm-y += nvkm/engine/disp/rootgt215.o
nvkm-y += nvkm/engine/disp/rootgf119.o
nvkm-y += nvkm/engine/disp/rootgk104.o
nvkm-y += nvkm/engine/disp/rootgk110.o
nvkm-y += nvkm/engine/disp/rootgm107.o
nvkm-y += nvkm/engine/disp/rootgm200.o
nvkm-y += nvkm/engine/disp/rootgp100.o
nvkm-y += nvkm/engine/disp/rootgp102.o
nvkm-y += nvkm/engine/disp/rootgv100.o
nvkm-y += nvkm/engine/disp/roottu102.o
nvkm-y += nvkm/engine/disp/rootga102.o
nvkm-y += nvkm/engine/disp/capsgv100.o
nvkm-y += nvkm/engine/disp/channv50.o
nvkm-y += nvkm/engine/disp/changf119.o
nvkm-y += nvkm/engine/disp/changv100.o
nvkm-y += nvkm/engine/disp/dmacnv50.o
nvkm-y += nvkm/engine/disp/dmacgf119.o
nvkm-y += nvkm/engine/disp/dmacgp102.o
nvkm-y += nvkm/engine/disp/dmacgv100.o
nvkm-y += nvkm/engine/disp/basenv50.o
nvkm-y += nvkm/engine/disp/baseg84.o
nvkm-y += nvkm/engine/disp/basegf119.o
nvkm-y += nvkm/engine/disp/basegp102.o
nvkm-y += nvkm/engine/disp/corenv50.o
nvkm-y += nvkm/engine/disp/coreg84.o
nvkm-y += nvkm/engine/disp/coreg94.o
nvkm-y += nvkm/engine/disp/coregf119.o
nvkm-y += nvkm/engine/disp/coregk104.o
nvkm-y += nvkm/engine/disp/coregp102.o
nvkm-y += nvkm/engine/disp/coregv100.o
nvkm-y += nvkm/engine/disp/ovlynv50.o
nvkm-y += nvkm/engine/disp/ovlyg84.o
nvkm-y += nvkm/engine/disp/ovlygt200.o
nvkm-y += nvkm/engine/disp/ovlygf119.o
nvkm-y += nvkm/engine/disp/ovlygk104.o
nvkm-y += nvkm/engine/disp/ovlygp102.o
nvkm-y += nvkm/engine/disp/wimmgv100.o
nvkm-y += nvkm/engine/disp/wndwgv100.o
nvkm-y += nvkm/engine/disp/piocnv50.o
nvkm-y += nvkm/engine/disp/piocgf119.o
nvkm-y += nvkm/engine/disp/cursnv50.o
nvkm-y += nvkm/engine/disp/cursgf119.o
nvkm-y += nvkm/engine/disp/cursgp102.o
nvkm-y += nvkm/engine/disp/cursgv100.o
nvkm-y += nvkm/engine/disp/oimmnv50.o nvkm-y += nvkm/engine/disp/udisp.o
nvkm-y += nvkm/engine/disp/oimmgf119.o nvkm-y += nvkm/engine/disp/uconn.o
nvkm-y += nvkm/engine/disp/oimmgp102.o nvkm-y += nvkm/engine/disp/uoutp.o
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <core/client.h> #include <core/client.h>
#include <core/notify.h> #include <core/notify.h>
#include <core/oproxy.h> #include <core/ramht.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
...@@ -108,7 +108,7 @@ nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size, ...@@ -108,7 +108,7 @@ nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size,
if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) { if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) {
notify->size = sizeof(struct nvif_notify_conn_rep_v0); notify->size = sizeof(struct nvif_notify_conn_rep_v0);
list_for_each_entry(outp, &disp->outp, head) { list_for_each_entry(outp, &disp->outps, head) {
if (ret = -ENXIO, outp->conn->index == req->v0.conn) { if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
if (ret = -ENODEV, outp->conn->hpd.event) { if (ret = -ENODEV, outp->conn->hpd.event) {
notify->types = req->v0.mask; notify->types = req->v0.mask;
...@@ -145,45 +145,12 @@ nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event) ...@@ -145,45 +145,12 @@ nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event)
return -EINVAL; return -EINVAL;
} }
static void
nvkm_disp_class_del(struct nvkm_oproxy *oproxy)
{
struct nvkm_disp *disp = nvkm_disp(oproxy->base.engine);
spin_lock(&disp->client.lock);
if (disp->client.object == oproxy)
disp->client.object = NULL;
spin_unlock(&disp->client.lock);
}
static const struct nvkm_oproxy_func
nvkm_disp_class = {
.dtor[1] = nvkm_disp_class_del,
};
static int static int
nvkm_disp_class_new(struct nvkm_device *device, nvkm_disp_class_new(struct nvkm_device *device,
const struct nvkm_oclass *oclass, void *data, u32 size, const struct nvkm_oclass *oclass, void *data, u32 size,
struct nvkm_object **pobject) struct nvkm_object **pobject)
{ {
const struct nvkm_disp_oclass *sclass = oclass->engn; return nvkm_udisp_new(oclass, data, size, pobject);
struct nvkm_disp *disp = nvkm_disp(oclass->engine);
struct nvkm_oproxy *oproxy;
int ret;
ret = nvkm_oproxy_new_(&nvkm_disp_class, oclass, &oproxy);
if (ret)
return ret;
*pobject = &oproxy->base;
spin_lock(&disp->client.lock);
if (disp->client.object) {
spin_unlock(&disp->client.lock);
return -EBUSY;
}
disp->client.object = oproxy;
spin_unlock(&disp->client.lock);
return sclass->ctor(disp, oclass, data, size, &oproxy->object);
} }
static const struct nvkm_device_oclass static const struct nvkm_device_oclass
...@@ -197,9 +164,7 @@ nvkm_disp_class_get(struct nvkm_oclass *oclass, int index, ...@@ -197,9 +164,7 @@ nvkm_disp_class_get(struct nvkm_oclass *oclass, int index,
{ {
struct nvkm_disp *disp = nvkm_disp(oclass->engine); struct nvkm_disp *disp = nvkm_disp(oclass->engine);
if (index == 0) { if (index == 0) {
const struct nvkm_disp_oclass *root = disp->func->root(disp); oclass->base = disp->func->root;
oclass->base = root->base;
oclass->engn = root;
*class = &nvkm_disp_sclass; *class = &nvkm_disp_sclass;
return 0; return 0;
} }
...@@ -223,11 +188,11 @@ nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) ...@@ -223,11 +188,11 @@ nvkm_disp_fini(struct nvkm_engine *engine, bool suspend)
if (disp->func->fini) if (disp->func->fini)
disp->func->fini(disp); disp->func->fini(disp);
list_for_each_entry(outp, &disp->outp, head) { list_for_each_entry(outp, &disp->outps, head) {
nvkm_outp_fini(outp); nvkm_outp_fini(outp);
} }
list_for_each_entry(conn, &disp->conn, head) { list_for_each_entry(conn, &disp->conns, head) {
nvkm_conn_fini(conn); nvkm_conn_fini(conn);
} }
...@@ -242,11 +207,11 @@ nvkm_disp_init(struct nvkm_engine *engine) ...@@ -242,11 +207,11 @@ nvkm_disp_init(struct nvkm_engine *engine)
struct nvkm_outp *outp; struct nvkm_outp *outp;
struct nvkm_ior *ior; struct nvkm_ior *ior;
list_for_each_entry(conn, &disp->conn, head) { list_for_each_entry(conn, &disp->conns, head) {
nvkm_conn_init(conn); nvkm_conn_init(conn);
} }
list_for_each_entry(outp, &disp->outp, head) { list_for_each_entry(outp, &disp->outps, head) {
nvkm_outp_init(outp); nvkm_outp_init(outp);
} }
...@@ -259,7 +224,7 @@ nvkm_disp_init(struct nvkm_engine *engine) ...@@ -259,7 +224,7 @@ nvkm_disp_init(struct nvkm_engine *engine)
/* Set 'normal' (ie. when it's attached to a head) state for /* Set 'normal' (ie. when it's attached to a head) state for
* each output resource to 'fully enabled'. * each output resource to 'fully enabled'.
*/ */
list_for_each_entry(ior, &disp->ior, head) { list_for_each_entry(ior, &disp->iors, head) {
ior->func->power(ior, true, true, true, true, true); ior->func->power(ior, true, true, true, true, true);
} }
...@@ -326,12 +291,12 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) ...@@ -326,12 +291,12 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
continue; continue;
} }
list_add_tail(&outp->head, &disp->outp); list_add_tail(&outp->head, &disp->outps);
hpd = max(hpd, (u8)(dcbE.connector + 1)); hpd = max(hpd, (u8)(dcbE.connector + 1));
} }
/* Create connector objects based on available output paths. */ /* Create connector objects based on available output paths. */
list_for_each_entry_safe(outp, outt, &disp->outp, head) { list_for_each_entry_safe(outp, outt, &disp->outps, head) {
/* VBIOS data *should* give us the most useful information. */ /* VBIOS data *should* give us the most useful information. */
data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
&connE); &connE);
...@@ -345,7 +310,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) ...@@ -345,7 +310,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
*/ */
int ccb_index = outp->info.i2c_index; int ccb_index = outp->info.i2c_index;
if (ccb_index != 0xf) { if (ccb_index != 0xf) {
list_for_each_entry(pair, &disp->outp, head) { list_for_each_entry(pair, &disp->outps, head) {
if (pair->info.i2c_index == ccb_index) { if (pair->info.i2c_index == ccb_index) {
outp->conn = pair->conn; outp->conn = pair->conn;
break; break;
...@@ -365,7 +330,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) ...@@ -365,7 +330,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
} }
/* Check that we haven't already created this connector. */ /* Check that we haven't already created this connector. */
list_for_each_entry(conn, &disp->conn, head) { list_for_each_entry(conn, &disp->conns, head) {
if (conn->index == outp->info.connector) { if (conn->index == outp->info.connector) {
outp->conn = conn; outp->conn = conn;
break; break;
...@@ -387,7 +352,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) ...@@ -387,7 +352,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
continue; continue;
} }
list_add_tail(&outp->conn->head, &disp->conn); list_add_tail(&outp->conn->head, &disp->conns);
} }
ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd); ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd);
...@@ -403,7 +368,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) ...@@ -403,7 +368,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
/* Enforce identity-mapped SOR assignment for panels, which have /* Enforce identity-mapped SOR assignment for panels, which have
* certain bits (ie. backlight controls) wired to a specific SOR. * certain bits (ie. backlight controls) wired to a specific SOR.
*/ */
list_for_each_entry(outp, &disp->outp, head) { list_for_each_entry(outp, &disp->outps, head) {
if (outp->conn->info.type == DCB_CONNECTOR_LVDS || if (outp->conn->info.type == DCB_CONNECTOR_LVDS ||
outp->conn->info.type == DCB_CONNECTOR_eDP) { outp->conn->info.type == DCB_CONNECTOR_eDP) {
ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1); ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1);
...@@ -414,7 +379,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) ...@@ -414,7 +379,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
} }
i = 0; i = 0;
list_for_each_entry(head, &disp->head, head) list_for_each_entry(head, &disp->heads, head)
i = max(i, head->id + 1); i = max(i, head->id + 1);
return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank); return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank);
...@@ -426,35 +391,42 @@ nvkm_disp_dtor(struct nvkm_engine *engine) ...@@ -426,35 +391,42 @@ nvkm_disp_dtor(struct nvkm_engine *engine)
struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_disp *disp = nvkm_disp(engine);
struct nvkm_conn *conn; struct nvkm_conn *conn;
struct nvkm_outp *outp; struct nvkm_outp *outp;
struct nvkm_ior *ior;
struct nvkm_head *head;
void *data = disp; void *data = disp;
if (disp->func->dtor) nvkm_ramht_del(&disp->ramht);
data = disp->func->dtor(disp); nvkm_gpuobj_del(&disp->inst);
nvkm_event_fini(&disp->uevent);
if (disp->super.wq) {
destroy_workqueue(disp->super.wq);
mutex_destroy(&disp->super.mutex);
}
nvkm_event_fini(&disp->vblank); nvkm_event_fini(&disp->vblank);
nvkm_event_fini(&disp->hpd); nvkm_event_fini(&disp->hpd);
while (!list_empty(&disp->conn)) { while (!list_empty(&disp->conns)) {
conn = list_first_entry(&disp->conn, typeof(*conn), head); conn = list_first_entry(&disp->conns, typeof(*conn), head);
list_del(&conn->head); list_del(&conn->head);
nvkm_conn_del(&conn); nvkm_conn_del(&conn);
} }
while (!list_empty(&disp->outp)) { while (!list_empty(&disp->outps)) {
outp = list_first_entry(&disp->outp, typeof(*outp), head); outp = list_first_entry(&disp->outps, typeof(*outp), head);
list_del(&outp->head); list_del(&outp->head);
nvkm_outp_del(&outp); nvkm_outp_del(&outp);
} }
while (!list_empty(&disp->ior)) { while (!list_empty(&disp->iors)) {
struct nvkm_ior *ior = ior = list_first_entry(&disp->iors, typeof(*ior), head);
list_first_entry(&disp->ior, typeof(*ior), head);
nvkm_ior_del(&ior); nvkm_ior_del(&ior);
} }
while (!list_empty(&disp->head)) { while (!list_empty(&disp->heads)) {
struct nvkm_head *head = head = list_first_entry(&disp->heads, typeof(*head), head);
list_first_entry(&disp->head, typeof(*head), head);
nvkm_head_del(&head); nvkm_head_del(&head);
} }
...@@ -471,24 +443,35 @@ nvkm_disp = { ...@@ -471,24 +443,35 @@ nvkm_disp = {
.base.sclass = nvkm_disp_class_get, .base.sclass = nvkm_disp_class_get,
}; };
int
nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_disp *disp)
{
disp->func = func;
INIT_LIST_HEAD(&disp->head);
INIT_LIST_HEAD(&disp->ior);
INIT_LIST_HEAD(&disp->outp);
INIT_LIST_HEAD(&disp->conn);
spin_lock_init(&disp->client.lock);
return nvkm_engine_ctor(&nvkm_disp, device, type, inst, true, &disp->engine);
}
int int
nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device, nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device,
enum nvkm_subdev_type type, int inst, struct nvkm_disp **pdisp) enum nvkm_subdev_type type, int inst, struct nvkm_disp **pdisp)
{ {
if (!(*pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL))) struct nvkm_disp *disp;
int ret;
if (!(disp = *pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
return nvkm_disp_ctor(func, device, type, inst, *pdisp);
disp->func = func;
INIT_LIST_HEAD(&disp->heads);
INIT_LIST_HEAD(&disp->iors);
INIT_LIST_HEAD(&disp->outps);
INIT_LIST_HEAD(&disp->conns);
spin_lock_init(&disp->client.lock);
ret = nvkm_engine_ctor(&nvkm_disp, device, type, inst, true, &disp->engine);
if (ret)
return ret;
if (func->super) {
disp->super.wq = create_singlethread_workqueue("nvkm-disp");
if (!disp->super.wq)
return -ENOMEM;
INIT_WORK(&disp->super.work, func->super);
mutex_init(&disp->super.mutex);
}
return nvkm_event_init(func->uevent, 1, ARRAY_SIZE(disp->chan), &disp->uevent);
} }
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
g84_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x0008c4 },
{ 0x0088, 0x0008d0 },
{ 0x008c, 0x0008dc },
{ 0x0090, 0x0008e4 },
{ 0x0094, 0x610884 },
{ 0x00a0, 0x6108a0 },
{ 0x00a4, 0x610878 },
{ 0x00c0, 0x61086c },
{ 0x00c4, 0x610800 },
{ 0x00c8, 0x61080c },
{ 0x00cc, 0x610818 },
{ 0x00e0, 0x610858 },
{ 0x00e4, 0x610860 },
{ 0x00e8, 0x6108ac },
{ 0x00ec, 0x6108b4 },
{ 0x00fc, 0x610824 },
{ 0x0100, 0x610894 },
{ 0x0104, 0x61082c },
{ 0x0110, 0x6108bc },
{ 0x0114, 0x61088c },
{}
}
};
static const struct nv50_disp_chan_mthd
g84_disp_base_mthd = {
.name = "Base",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &g84_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_base_mthd_image },
{}
}
};
int
g84_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&nv50_disp_dmac_func, &g84_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
gf119_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x661080 },
{ 0x0084, 0x661084 },
{ 0x0088, 0x661088 },
{ 0x008c, 0x66108c },
{ 0x0090, 0x661090 },
{ 0x0094, 0x661094 },
{ 0x00a0, 0x6610a0 },
{ 0x00a4, 0x6610a4 },
{ 0x00c0, 0x6610c0 },
{ 0x00c4, 0x6610c4 },
{ 0x00c8, 0x6610c8 },
{ 0x00cc, 0x6610cc },
{ 0x00e0, 0x6610e0 },
{ 0x00e4, 0x6610e4 },
{ 0x00e8, 0x6610e8 },
{ 0x00ec, 0x6610ec },
{ 0x00fc, 0x6610fc },
{ 0x0100, 0x661100 },
{ 0x0104, 0x661104 },
{ 0x0108, 0x661108 },
{ 0x010c, 0x66110c },
{ 0x0110, 0x661110 },
{ 0x0114, 0x661114 },
{ 0x0118, 0x661118 },
{ 0x011c, 0x66111c },
{ 0x0130, 0x661130 },
{ 0x0134, 0x661134 },
{ 0x0138, 0x661138 },
{ 0x013c, 0x66113c },
{ 0x0140, 0x661140 },
{ 0x0144, 0x661144 },
{ 0x0148, 0x661148 },
{ 0x014c, 0x66114c },
{ 0x0150, 0x661150 },
{ 0x0154, 0x661154 },
{ 0x0158, 0x661158 },
{ 0x015c, 0x66115c },
{ 0x0160, 0x661160 },
{ 0x0164, 0x661164 },
{ 0x0168, 0x661168 },
{ 0x016c, 0x66116c },
{}
}
};
static const struct nv50_disp_mthd_list
gf119_disp_base_mthd_image = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0400, 0x661400 },
{ 0x0404, 0x661404 },
{ 0x0408, 0x661408 },
{ 0x040c, 0x66140c },
{ 0x0410, 0x661410 },
{}
}
};
const struct nv50_disp_chan_mthd
gf119_disp_base_mthd = {
.name = "Base",
.addr = 0x001000,
.prev = -0x020000,
.data = {
{ "Global", 1, &gf119_disp_base_mthd_base },
{ "Image", 2, &gf119_disp_base_mthd_image },
{}
}
};
int
gf119_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&gf119_disp_dmac_func, &gf119_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/*
* Copyright 2016 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
int
gp102_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&gp102_disp_dmac_func, &gf119_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include "head.h"
#include <core/client.h>
#include <nvif/cl507c.h>
#include <nvif/unpack.h>
int
nv50_disp_base_new_(const struct nv50_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd,
struct nv50_disp *disp, int chid,
const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
union {
struct nv50_disp_base_channel_dma_v0 v0;
} *args = argv;
struct nvkm_object *parent = oclass->parent;
int head, ret = -ENOSYS;
u64 push;
nvif_ioctl(parent, "create disp base channel dma size %d\n", argc);
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp base channel dma vers %d "
"pushbuf %016llx head %d\n",
args->v0.version, args->v0.pushbuf, args->v0.head);
if (!nvkm_head_find(&disp->base, args->v0.head))
return -EINVAL;
push = args->v0.pushbuf;
head = args->v0.head;
} else
return ret;
return nv50_disp_dmac_new_(func, mthd, disp, chid + head,
head, push, oclass, pobject);
}
static const struct nv50_disp_mthd_list
nv50_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x0008c4 },
{ 0x0088, 0x0008d0 },
{ 0x008c, 0x0008dc },
{ 0x0090, 0x0008e4 },
{ 0x0094, 0x610884 },
{ 0x00a0, 0x6108a0 },
{ 0x00a4, 0x610878 },
{ 0x00c0, 0x61086c },
{ 0x00e0, 0x610858 },
{ 0x00e4, 0x610860 },
{ 0x00e8, 0x6108ac },
{ 0x00ec, 0x6108b4 },
{ 0x0100, 0x610894 },
{ 0x0110, 0x6108bc },
{ 0x0114, 0x61088c },
{}
}
};
const struct nv50_disp_mthd_list
nv50_disp_base_mthd_image = {
.mthd = 0x0400,
.addr = 0x000000,
.data = {
{ 0x0800, 0x6108f0 },
{ 0x0804, 0x6108fc },
{ 0x0808, 0x61090c },
{ 0x080c, 0x610914 },
{ 0x0810, 0x610904 },
{}
}
};
static const struct nv50_disp_chan_mthd
nv50_disp_base_mthd = {
.name = "Base",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_base_mthd_image },
{}
}
};
int
nv50_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_base_new_(&nv50_disp_dmac_func, &nv50_disp_base_mthd,
disp, 1, oclass, argv, argc, pobject);
}
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_DISP_CHAN_H__
#define __NVKM_DISP_CHAN_H__
#define nvkm_disp_chan(p) container_of((p), struct nvkm_disp_chan, object)
#include <core/object.h>
#include "priv.h"
struct nvkm_disp_chan {
const struct nvkm_disp_chan_func *func;
const struct nvkm_disp_chan_mthd *mthd;
struct nvkm_disp *disp;
struct {
int ctrl;
int user;
} chid;
int head;
struct nvkm_object object;
struct nvkm_memory *memory;
u64 push;
u32 suspend_put;
};
int nvkm_disp_core_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
int nvkm_disp_chan_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
int nvkm_disp_wndw_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
struct nvkm_disp_chan_func {
int (*push)(struct nvkm_disp_chan *, u64 object);
int (*init)(struct nvkm_disp_chan *);
void (*fini)(struct nvkm_disp_chan *);
void (*intr)(struct nvkm_disp_chan *, bool en);
u64 (*user)(struct nvkm_disp_chan *, u64 *size);
int (*bind)(struct nvkm_disp_chan *, struct nvkm_object *, u32 handle);
};
void nv50_disp_chan_intr(struct nvkm_disp_chan *, bool);
u64 nv50_disp_chan_user(struct nvkm_disp_chan *, u64 *);
extern const struct nvkm_disp_chan_func nv50_disp_pioc_func;
extern const struct nvkm_disp_chan_func nv50_disp_dmac_func;
int nv50_disp_dmac_push(struct nvkm_disp_chan *, u64);
int nv50_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
extern const struct nvkm_disp_chan_func nv50_disp_core_func;
void gf119_disp_chan_intr(struct nvkm_disp_chan *, bool);
extern const struct nvkm_disp_chan_func gf119_disp_pioc_func;
extern const struct nvkm_disp_chan_func gf119_disp_dmac_func;
void gf119_disp_dmac_fini(struct nvkm_disp_chan *);
int gf119_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
extern const struct nvkm_disp_chan_func gf119_disp_core_func;
void gf119_disp_core_fini(struct nvkm_disp_chan *);
extern const struct nvkm_disp_chan_func gp102_disp_dmac_func;
u64 gv100_disp_chan_user(struct nvkm_disp_chan *, u64 *);
int gv100_disp_dmac_init(struct nvkm_disp_chan *);
void gv100_disp_dmac_fini(struct nvkm_disp_chan *);
int gv100_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
struct nvkm_disp_chan_user {
const struct nvkm_disp_chan_func *func;
int ctrl;
int user;
const struct nvkm_disp_chan_mthd *mthd;
};
extern const struct nvkm_disp_chan_user nv50_disp_oimm;
extern const struct nvkm_disp_chan_user nv50_disp_curs;
extern const struct nvkm_disp_chan_user g84_disp_core;
extern const struct nvkm_disp_chan_user g84_disp_base;
extern const struct nvkm_disp_chan_user g84_disp_ovly;
extern const struct nvkm_disp_chan_user g94_disp_core;
extern const struct nvkm_disp_chan_user gt200_disp_ovly;
extern const struct nvkm_disp_chan_user gf119_disp_base;
extern const struct nvkm_disp_chan_user gf119_disp_oimm;
extern const struct nvkm_disp_chan_user gf119_disp_curs;
extern const struct nvkm_disp_chan_user gk104_disp_core;
extern const struct nvkm_disp_chan_user gk104_disp_ovly;
extern const struct nvkm_disp_chan_user gv100_disp_core;
extern const struct nvkm_disp_chan_user gv100_disp_curs;
extern const struct nvkm_disp_chan_user gv100_disp_wndw;
extern const struct nvkm_disp_chan_user gv100_disp_wimm;
struct nvkm_disp_mthd_list {
u32 mthd;
u32 addr;
struct {
u32 mthd;
u32 addr;
const char *name;
} data[];
};
struct nvkm_disp_chan_mthd {
const char *name;
u32 addr;
s32 prev;
struct {
const char *name;
int nr;
const struct nvkm_disp_mthd_list *mthd;
} data[];
};
void nv50_disp_chan_mthd(struct nvkm_disp_chan *, int debug);
extern const struct nvkm_disp_mthd_list nv50_disp_core_mthd_base;
extern const struct nvkm_disp_mthd_list nv50_disp_core_mthd_sor;
extern const struct nvkm_disp_mthd_list nv50_disp_core_mthd_pior;
extern const struct nvkm_disp_mthd_list nv50_disp_base_mthd_image;
extern const struct nvkm_disp_chan_mthd g84_disp_core_mthd;
extern const struct nvkm_disp_mthd_list g84_disp_core_mthd_dac;
extern const struct nvkm_disp_mthd_list g84_disp_core_mthd_head;
extern const struct nvkm_disp_chan_mthd g94_disp_core_mthd;
extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_base;
extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_dac;
extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_sor;
extern const struct nvkm_disp_mthd_list gf119_disp_core_mthd_pior;
extern const struct nvkm_disp_chan_mthd gf119_disp_base_mthd;
extern const struct nvkm_disp_chan_mthd gk104_disp_core_mthd;
extern const struct nvkm_disp_chan_mthd gk104_disp_ovly_mthd;
#endif
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static void
gf119_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nv50_disp *disp = container_of(event, typeof(*disp), uevent);
struct nvkm_device *device = disp->base.engine.subdev.device;
nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000000 << index);
nvkm_wr32(device, 0x61008c, 0x00000001 << index);
}
static void
gf119_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{
struct nv50_disp *disp = container_of(event, typeof(*disp), uevent);
struct nvkm_device *device = disp->base.engine.subdev.device;
nvkm_wr32(device, 0x61008c, 0x00000001 << index);
nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000001 << index);
}
const struct nvkm_event_func
gf119_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
.init = gf119_disp_chan_uevent_init,
.fini = gf119_disp_chan_uevent_fini,
};
void
gf119_disp_chan_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 mask = 0x00000001 << chan->chid.user;
if (!en) {
nvkm_mask(device, 0x610090, mask, 0x00000000);
nvkm_mask(device, 0x6100a0, mask, 0x00000000);
} else {
nvkm_mask(device, 0x6100a0, mask, mask);
}
}
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "channv50.h"
const struct nvkm_event_func
gv100_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
};
u64
gv100_disp_chan_user(struct nv50_disp_chan *chan, u64 *psize)
{
*psize = 0x1000;
return 0x690000 + ((chan->chid.user - 1) * 0x1000);
}
/* SPDX-License-Identifier: MIT */
#ifndef __NV50_DISP_CHAN_H__
#define __NV50_DISP_CHAN_H__
#define nv50_disp_chan(p) container_of((p), struct nv50_disp_chan, object)
#include <core/object.h>
#include "nv50.h"
struct nv50_disp_root;
struct nv50_disp_chan {
const struct nv50_disp_chan_func *func;
const struct nv50_disp_chan_mthd *mthd;
struct nv50_disp *disp;
struct {
int ctrl;
int user;
} chid;
int head;
struct nvkm_object object;
struct nvkm_memory *memory;
u64 push;
u32 suspend_put;
};
struct nv50_disp_chan_func {
int (*init)(struct nv50_disp_chan *);
void (*fini)(struct nv50_disp_chan *);
void (*intr)(struct nv50_disp_chan *, bool en);
u64 (*user)(struct nv50_disp_chan *, u64 *size);
int (*bind)(struct nv50_disp_chan *, struct nvkm_object *, u32 handle);
};
int nv50_disp_chan_new_(const struct nv50_disp_chan_func *,
const struct nv50_disp_chan_mthd *,
struct nv50_disp *, int ctrl, int user, int head,
const struct nvkm_oclass *, struct nvkm_object **);
int nv50_disp_dmac_new_(const struct nv50_disp_chan_func *,
const struct nv50_disp_chan_mthd *,
struct nv50_disp *, int chid, int head, u64 push,
const struct nvkm_oclass *, struct nvkm_object **);
void nv50_disp_chan_intr(struct nv50_disp_chan *, bool);
u64 nv50_disp_chan_user(struct nv50_disp_chan *, u64 *);
extern const struct nv50_disp_chan_func nv50_disp_pioc_func;
extern const struct nv50_disp_chan_func nv50_disp_dmac_func;
int nv50_disp_dmac_bind(struct nv50_disp_chan *, struct nvkm_object *, u32);
extern const struct nv50_disp_chan_func nv50_disp_core_func;
void gf119_disp_chan_intr(struct nv50_disp_chan *, bool);
extern const struct nv50_disp_chan_func gf119_disp_pioc_func;
extern const struct nv50_disp_chan_func gf119_disp_dmac_func;
void gf119_disp_dmac_fini(struct nv50_disp_chan *);
int gf119_disp_dmac_bind(struct nv50_disp_chan *, struct nvkm_object *, u32);
extern const struct nv50_disp_chan_func gf119_disp_core_func;
void gf119_disp_core_fini(struct nv50_disp_chan *);
extern const struct nv50_disp_chan_func gp102_disp_dmac_func;
u64 gv100_disp_chan_user(struct nv50_disp_chan *, u64 *);
int gv100_disp_dmac_init(struct nv50_disp_chan *);
void gv100_disp_dmac_fini(struct nv50_disp_chan *);
int gv100_disp_dmac_bind(struct nv50_disp_chan *, struct nvkm_object *, u32);
int nv50_disp_curs_new_(const struct nv50_disp_chan_func *,
struct nv50_disp *, int ctrl, int user,
const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **);
int nv50_disp_oimm_new_(const struct nv50_disp_chan_func *,
struct nv50_disp *, int ctrl, int user,
const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **);
int nv50_disp_base_new_(const struct nv50_disp_chan_func *,
const struct nv50_disp_chan_mthd *,
struct nv50_disp *, int chid,
const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **);
int nv50_disp_core_new_(const struct nv50_disp_chan_func *,
const struct nv50_disp_chan_mthd *,
struct nv50_disp *, int chid,
const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **);
int nv50_disp_ovly_new_(const struct nv50_disp_chan_func *,
const struct nv50_disp_chan_mthd *,
struct nv50_disp *, int chid,
const struct nvkm_oclass *, void *argv, u32 argc,
struct nvkm_object **);
int nv50_disp_curs_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int nv50_disp_oimm_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int nv50_disp_base_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int nv50_disp_core_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int nv50_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int g84_disp_base_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int g84_disp_core_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int g84_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int g94_disp_core_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gt200_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gf119_disp_curs_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gf119_disp_oimm_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gf119_disp_base_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gf119_disp_core_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gf119_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gk104_disp_core_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gk104_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gp102_disp_curs_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gp102_disp_oimm_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gp102_disp_base_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gp102_disp_core_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gp102_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gv100_disp_curs_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gv100_disp_wimm_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gv100_disp_core_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
int gv100_disp_wndw_new(const struct nvkm_oclass *, void *, u32,
struct nv50_disp *, struct nvkm_object **);
struct nv50_disp_mthd_list {
u32 mthd;
u32 addr;
struct {
u32 mthd;
u32 addr;
const char *name;
} data[];
};
struct nv50_disp_chan_mthd {
const char *name;
u32 addr;
s32 prev;
struct {
const char *name;
int nr;
const struct nv50_disp_mthd_list *mthd;
} data[];
};
void nv50_disp_chan_mthd(struct nv50_disp_chan *, int debug);
extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base;
extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor;
extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior;
extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image;
extern const struct nv50_disp_chan_mthd g84_disp_core_mthd;
extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac;
extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head;
extern const struct nv50_disp_chan_mthd g94_disp_core_mthd;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_base;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_dac;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_sor;
extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_pior;
extern const struct nv50_disp_chan_mthd gf119_disp_base_mthd;
extern const struct nv50_disp_chan_mthd gk104_disp_core_mthd;
extern const struct nv50_disp_chan_mthd gk104_disp_ovly_mthd;
#endif
...@@ -86,6 +86,7 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info, ...@@ -86,6 +86,7 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
conn->disp = disp; conn->disp = disp;
conn->index = index; conn->index = index;
conn->info = *info; conn->info = *info;
conn->info.hpd = DCB_GPIO_UNUSED;
CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x", CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x",
info->type, info->location, info->hpd, info->dp, info->type, info->location, info->hpd, info->dp,
...@@ -100,11 +101,12 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info, ...@@ -100,11 +101,12 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
ret = nvkm_gpio_find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); ret = nvkm_gpio_find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
if (ret) { if (ret) {
CONN_ERR(conn, "func %02x lookup failed, %d", CONN_ERR(conn, "func %02x lookup failed, %d", info->hpd, ret);
info->hpd, ret);
return; return;
} }
conn->info.hpd = func.line;
ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd, ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd,
true, &(struct nvkm_gpio_ntfy_req) { true, &(struct nvkm_gpio_ntfy_req) {
.mask = NVKM_GPIO_TOGGLED, .mask = NVKM_GPIO_TOGGLED,
......
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
#ifndef __NVKM_DISP_CONN_H__ #ifndef __NVKM_DISP_CONN_H__
#define __NVKM_DISP_CONN_H__ #define __NVKM_DISP_CONN_H__
#include <engine/disp.h> #include "priv.h"
#include <core/notify.h> #include <core/notify.h>
#include <subdev/bios.h> #include <subdev/bios.h>
...@@ -15,6 +15,8 @@ struct nvkm_conn { ...@@ -15,6 +15,8 @@ struct nvkm_conn {
struct nvkm_notify hpd; struct nvkm_notify hpd;
struct list_head head; struct list_head head;
struct nvkm_object object;
}; };
int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *, int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *,
......
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
const struct nv50_disp_mthd_list
g84_disp_core_mthd_dac = {
.mthd = 0x0080,
.addr = 0x000008,
.data = {
{ 0x0400, 0x610b58 },
{ 0x0404, 0x610bdc },
{ 0x0420, 0x610bc4 },
{}
}
};
const struct nv50_disp_mthd_list
g84_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000540,
.data = {
{ 0x0800, 0x610ad8 },
{ 0x0804, 0x610ad0 },
{ 0x0808, 0x610a48 },
{ 0x080c, 0x610a78 },
{ 0x0810, 0x610ac0 },
{ 0x0814, 0x610af8 },
{ 0x0818, 0x610b00 },
{ 0x081c, 0x610ae8 },
{ 0x0820, 0x610af0 },
{ 0x0824, 0x610b08 },
{ 0x0828, 0x610b10 },
{ 0x082c, 0x610a68 },
{ 0x0830, 0x610a60 },
{ 0x0834, 0x000000 },
{ 0x0838, 0x610a40 },
{ 0x0840, 0x610a24 },
{ 0x0844, 0x610a2c },
{ 0x0848, 0x610aa8 },
{ 0x084c, 0x610ab0 },
{ 0x085c, 0x610c5c },
{ 0x0860, 0x610a84 },
{ 0x0864, 0x610a90 },
{ 0x0868, 0x610b18 },
{ 0x086c, 0x610b20 },
{ 0x0870, 0x610ac8 },
{ 0x0874, 0x610a38 },
{ 0x0878, 0x610c50 },
{ 0x0880, 0x610a58 },
{ 0x0884, 0x610a9c },
{ 0x089c, 0x610c68 },
{ 0x08a0, 0x610a70 },
{ 0x08a4, 0x610a50 },
{ 0x08a8, 0x610ae0 },
{ 0x08c0, 0x610b28 },
{ 0x08c4, 0x610b30 },
{ 0x08c8, 0x610b40 },
{ 0x08d4, 0x610b38 },
{ 0x08d8, 0x610b48 },
{ 0x08dc, 0x610b50 },
{ 0x0900, 0x610a18 },
{ 0x0904, 0x610ab8 },
{ 0x0910, 0x610c70 },
{ 0x0914, 0x610c78 },
{}
}
};
const struct nv50_disp_chan_mthd
g84_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &g84_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &g84_disp_core_mthd_head },
{}
}
};
int
g84_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &g84_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
g94_disp_core_mthd_sor = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0600, 0x610794 },
{}
}
};
const struct nv50_disp_chan_mthd
g94_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &g84_disp_core_mthd_dac },
{ "SOR", 4, &g94_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &g84_disp_core_mthd_head },
{}
}
};
int
g94_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &g94_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include <subdev/timer.h>
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x660080 },
{ 0x0084, 0x660084 },
{ 0x0088, 0x660088 },
{ 0x008c, 0x000000 },
{}
}
};
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_dac = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0180, 0x660180 },
{ 0x0184, 0x660184 },
{ 0x0188, 0x660188 },
{ 0x0190, 0x660190 },
{}
}
};
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_sor = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0200, 0x660200 },
{ 0x0204, 0x660204 },
{ 0x0208, 0x660208 },
{ 0x0210, 0x660210 },
{}
}
};
const struct nv50_disp_mthd_list
gf119_disp_core_mthd_pior = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0300, 0x660300 },
{ 0x0304, 0x660304 },
{ 0x0308, 0x660308 },
{ 0x0310, 0x660310 },
{}
}
};
static const struct nv50_disp_mthd_list
gf119_disp_core_mthd_head = {
.mthd = 0x0300,
.addr = 0x000300,
.data = {
{ 0x0400, 0x660400 },
{ 0x0404, 0x660404 },
{ 0x0408, 0x660408 },
{ 0x040c, 0x66040c },
{ 0x0410, 0x660410 },
{ 0x0414, 0x660414 },
{ 0x0418, 0x660418 },
{ 0x041c, 0x66041c },
{ 0x0420, 0x660420 },
{ 0x0424, 0x660424 },
{ 0x0428, 0x660428 },
{ 0x042c, 0x66042c },
{ 0x0430, 0x660430 },
{ 0x0434, 0x660434 },
{ 0x0438, 0x660438 },
{ 0x0440, 0x660440 },
{ 0x0444, 0x660444 },
{ 0x0448, 0x660448 },
{ 0x044c, 0x66044c },
{ 0x0450, 0x660450 },
{ 0x0454, 0x660454 },
{ 0x0458, 0x660458 },
{ 0x045c, 0x66045c },
{ 0x0460, 0x660460 },
{ 0x0468, 0x660468 },
{ 0x046c, 0x66046c },
{ 0x0470, 0x660470 },
{ 0x0474, 0x660474 },
{ 0x0480, 0x660480 },
{ 0x0484, 0x660484 },
{ 0x048c, 0x66048c },
{ 0x0490, 0x660490 },
{ 0x0494, 0x660494 },
{ 0x0498, 0x660498 },
{ 0x04b0, 0x6604b0 },
{ 0x04b8, 0x6604b8 },
{ 0x04bc, 0x6604bc },
{ 0x04c0, 0x6604c0 },
{ 0x04c4, 0x6604c4 },
{ 0x04c8, 0x6604c8 },
{ 0x04d0, 0x6604d0 },
{ 0x04d4, 0x6604d4 },
{ 0x04e0, 0x6604e0 },
{ 0x04e4, 0x6604e4 },
{ 0x04e8, 0x6604e8 },
{ 0x04ec, 0x6604ec },
{ 0x04f0, 0x6604f0 },
{ 0x04f4, 0x6604f4 },
{ 0x04f8, 0x6604f8 },
{ 0x04fc, 0x6604fc },
{ 0x0500, 0x660500 },
{ 0x0504, 0x660504 },
{ 0x0508, 0x660508 },
{ 0x050c, 0x66050c },
{ 0x0510, 0x660510 },
{ 0x0514, 0x660514 },
{ 0x0518, 0x660518 },
{ 0x051c, 0x66051c },
{ 0x052c, 0x66052c },
{ 0x0530, 0x660530 },
{ 0x054c, 0x66054c },
{ 0x0550, 0x660550 },
{ 0x0554, 0x660554 },
{ 0x0558, 0x660558 },
{ 0x055c, 0x66055c },
{}
}
};
static const struct nv50_disp_chan_mthd
gf119_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = -0x020000,
.data = {
{ "Global", 1, &gf119_disp_core_mthd_base },
{ "DAC", 3, &gf119_disp_core_mthd_dac },
{ "SOR", 8, &gf119_disp_core_mthd_sor },
{ "PIOR", 4, &gf119_disp_core_mthd_pior },
{ "HEAD", 4, &gf119_disp_core_mthd_head },
{}
}
};
void
gf119_disp_core_fini(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
/* deactivate channel */
nvkm_mask(device, 0x610490, 0x00000010, 0x00000000);
nvkm_mask(device, 0x610490, 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "core fini: %08x\n",
nvkm_rd32(device, 0x610490));
}
chan->suspend_put = nvkm_rd32(device, 0x640000);
}
static int
gf119_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x610494, chan->push);
nvkm_wr32(device, 0x610498, 0x00010000);
nvkm_wr32(device, 0x61049c, 0x00000001);
nvkm_mask(device, 0x610490, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000, chan->suspend_put);
nvkm_wr32(device, 0x610490, 0x01000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "core init: %08x\n",
nvkm_rd32(device, 0x610490));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
gf119_disp_core_func = {
.init = gf119_disp_core_init,
.fini = gf119_disp_core_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};
int
gf119_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gf119_disp_core_func, &gf119_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
static const struct nv50_disp_mthd_list
gk104_disp_core_mthd_head = {
.mthd = 0x0300,
.addr = 0x000300,
.data = {
{ 0x0400, 0x660400 },
{ 0x0404, 0x660404 },
{ 0x0408, 0x660408 },
{ 0x040c, 0x66040c },
{ 0x0410, 0x660410 },
{ 0x0414, 0x660414 },
{ 0x0418, 0x660418 },
{ 0x041c, 0x66041c },
{ 0x0420, 0x660420 },
{ 0x0424, 0x660424 },
{ 0x0428, 0x660428 },
{ 0x042c, 0x66042c },
{ 0x0430, 0x660430 },
{ 0x0434, 0x660434 },
{ 0x0438, 0x660438 },
{ 0x0440, 0x660440 },
{ 0x0444, 0x660444 },
{ 0x0448, 0x660448 },
{ 0x044c, 0x66044c },
{ 0x0450, 0x660450 },
{ 0x0454, 0x660454 },
{ 0x0458, 0x660458 },
{ 0x045c, 0x66045c },
{ 0x0460, 0x660460 },
{ 0x0468, 0x660468 },
{ 0x046c, 0x66046c },
{ 0x0470, 0x660470 },
{ 0x0474, 0x660474 },
{ 0x047c, 0x66047c },
{ 0x0480, 0x660480 },
{ 0x0484, 0x660484 },
{ 0x0488, 0x660488 },
{ 0x048c, 0x66048c },
{ 0x0490, 0x660490 },
{ 0x0494, 0x660494 },
{ 0x0498, 0x660498 },
{ 0x04a0, 0x6604a0 },
{ 0x04b0, 0x6604b0 },
{ 0x04b8, 0x6604b8 },
{ 0x04bc, 0x6604bc },
{ 0x04c0, 0x6604c0 },
{ 0x04c4, 0x6604c4 },
{ 0x04c8, 0x6604c8 },
{ 0x04d0, 0x6604d0 },
{ 0x04d4, 0x6604d4 },
{ 0x04e0, 0x6604e0 },
{ 0x04e4, 0x6604e4 },
{ 0x04e8, 0x6604e8 },
{ 0x04ec, 0x6604ec },
{ 0x04f0, 0x6604f0 },
{ 0x04f4, 0x6604f4 },
{ 0x04f8, 0x6604f8 },
{ 0x04fc, 0x6604fc },
{ 0x0500, 0x660500 },
{ 0x0504, 0x660504 },
{ 0x0508, 0x660508 },
{ 0x050c, 0x66050c },
{ 0x0510, 0x660510 },
{ 0x0514, 0x660514 },
{ 0x0518, 0x660518 },
{ 0x051c, 0x66051c },
{ 0x0520, 0x660520 },
{ 0x0524, 0x660524 },
{ 0x052c, 0x66052c },
{ 0x0530, 0x660530 },
{ 0x054c, 0x66054c },
{ 0x0550, 0x660550 },
{ 0x0554, 0x660554 },
{ 0x0558, 0x660558 },
{ 0x055c, 0x66055c },
{}
}
};
const struct nv50_disp_chan_mthd
gk104_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = -0x020000,
.data = {
{ "Global", 1, &gf119_disp_core_mthd_base },
{ "DAC", 3, &gf119_disp_core_mthd_dac },
{ "SOR", 8, &gf119_disp_core_mthd_sor },
{ "PIOR", 4, &gf119_disp_core_mthd_pior },
{ "HEAD", 4, &gk104_disp_core_mthd_head },
{}
}
};
int
gk104_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gf119_disp_core_func, &gk104_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2016 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
#include <subdev/timer.h>
static int
gp102_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x611494, chan->push);
nvkm_wr32(device, 0x611498, 0x00010000);
nvkm_wr32(device, 0x61149c, 0x00000001);
nvkm_mask(device, 0x610490, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000, chan->suspend_put);
nvkm_wr32(device, 0x610490, 0x01000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "core init: %08x\n",
nvkm_rd32(device, 0x610490));
return -EBUSY;
}
return 0;
}
static const struct nv50_disp_chan_func
gp102_disp_core_func = {
.init = gp102_disp_core_init,
.fini = gf119_disp_core_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};
int
gp102_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gp102_disp_core_func, &gk104_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "channv50.h"
#include <subdev/timer.h>
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0200, 0x680200 },
{ 0x0208, 0x680208 },
{ 0x020c, 0x68020c },
{ 0x0210, 0x680210 },
{ 0x0214, 0x680214 },
{ 0x0218, 0x680218 },
{ 0x021c, 0x68021c },
{}
}
};
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_sor = {
.mthd = 0x0020,
.addr = 0x000020,
.data = {
{ 0x0300, 0x680300 },
{ 0x0304, 0x680304 },
{ 0x0308, 0x680308 },
{ 0x030c, 0x68030c },
{}
}
};
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_wndw = {
.mthd = 0x0080,
.addr = 0x000080,
.data = {
{ 0x1000, 0x681000 },
{ 0x1004, 0x681004 },
{ 0x1008, 0x681008 },
{ 0x100c, 0x68100c },
{ 0x1010, 0x681010 },
{}
}
};
static const struct nv50_disp_mthd_list
gv100_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000400,
.data = {
{ 0x2000, 0x682000 },
{ 0x2004, 0x682004 },
{ 0x2008, 0x682008 },
{ 0x200c, 0x68200c },
{ 0x2014, 0x682014 },
{ 0x2018, 0x682018 },
{ 0x201c, 0x68201c },
{ 0x2020, 0x682020 },
{ 0x2028, 0x682028 },
{ 0x202c, 0x68202c },
{ 0x2030, 0x682030 },
{ 0x2038, 0x682038 },
{ 0x203c, 0x68203c },
{ 0x2048, 0x682048 },
{ 0x204c, 0x68204c },
{ 0x2050, 0x682050 },
{ 0x2054, 0x682054 },
{ 0x2058, 0x682058 },
{ 0x205c, 0x68205c },
{ 0x2060, 0x682060 },
{ 0x2064, 0x682064 },
{ 0x2068, 0x682068 },
{ 0x206c, 0x68206c },
{ 0x2070, 0x682070 },
{ 0x2074, 0x682074 },
{ 0x2078, 0x682078 },
{ 0x207c, 0x68207c },
{ 0x2080, 0x682080 },
{ 0x2088, 0x682088 },
{ 0x2090, 0x682090 },
{ 0x209c, 0x68209c },
{ 0x20a0, 0x6820a0 },
{ 0x20a4, 0x6820a4 },
{ 0x20a8, 0x6820a8 },
{ 0x20ac, 0x6820ac },
{ 0x2180, 0x682180 },
{ 0x2184, 0x682184 },
{ 0x218c, 0x68218c },
{ 0x2194, 0x682194 },
{ 0x2198, 0x682198 },
{ 0x219c, 0x68219c },
{ 0x21a0, 0x6821a0 },
{ 0x21a4, 0x6821a4 },
{ 0x2214, 0x682214 },
{ 0x2218, 0x682218 },
{}
}
};
static const struct nv50_disp_chan_mthd
gv100_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x008000,
.data = {
{ "Global", 1, &gv100_disp_core_mthd_base },
{ "SOR", 4, &gv100_disp_core_mthd_sor },
{ "WINDOW", 8, &gv100_disp_core_mthd_wndw },
{ "HEAD", 4, &gv100_disp_core_mthd_head },
{}
}
};
static int
gv100_disp_core_idle(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
nvkm_msec(device, 2000,
u32 stat = nvkm_rd32(device, 0x610630);
if ((stat & 0x001f0000) == 0x000b0000)
return 0;
);
return -EBUSY;
}
static u64
gv100_disp_core_user(struct nv50_disp_chan *chan, u64 *psize)
{
*psize = 0x10000;
return 0x680000;
}
static void
gv100_disp_core_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 mask = 0x00000001;
const u32 data = en ? mask : 0;
nvkm_mask(device, 0x611dac, mask, data);
}
static void
gv100_disp_core_fini(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
nvkm_mask(device, 0x6104e0, 0x00000010, 0x00000000);
gv100_disp_core_idle(chan);
nvkm_mask(device, 0x6104e0, 0x00000002, 0x00000000);
chan->suspend_put = nvkm_rd32(device, 0x680000);
}
static int
gv100_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
nvkm_wr32(device, 0x610b24, lower_32_bits(chan->push));
nvkm_wr32(device, 0x610b20, upper_32_bits(chan->push));
nvkm_wr32(device, 0x610b28, 0x00000001);
nvkm_wr32(device, 0x610b2c, 0x00000040);
nvkm_mask(device, 0x6104e0, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x680000, chan->suspend_put);
nvkm_wr32(device, 0x6104e0, 0x00000013);
return gv100_disp_core_idle(chan);
}
static const struct nv50_disp_chan_func
gv100_disp_core = {
.init = gv100_disp_core_init,
.fini = gv100_disp_core_fini,
.intr = gv100_disp_core_intr,
.user = gv100_disp_core_user,
.bind = gv100_disp_dmac_bind,
};
int
gv100_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&gv100_disp_core, &gv100_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include <core/client.h>
#include <subdev/timer.h>
#include <nvif/cl507d.h>
#include <nvif/unpack.h>
int
nv50_disp_core_new_(const struct nv50_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd,
struct nv50_disp *disp, int chid,
const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
union {
struct nv50_disp_core_channel_dma_v0 v0;
} *args = argv;
struct nvkm_object *parent = oclass->parent;
u64 push;
int ret = -ENOSYS;
nvif_ioctl(parent, "create disp core channel dma size %d\n", argc);
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp core channel dma vers %d "
"pushbuf %016llx\n",
args->v0.version, args->v0.pushbuf);
push = args->v0.pushbuf;
} else
return ret;
return nv50_disp_dmac_new_(func, mthd, disp, chid, 0,
push, oclass, pobject);
}
const struct nv50_disp_mthd_list
nv50_disp_core_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x610bb8 },
{ 0x0088, 0x610b9c },
{ 0x008c, 0x000000 },
{}
}
};
static const struct nv50_disp_mthd_list
nv50_disp_core_mthd_dac = {
.mthd = 0x0080,
.addr = 0x000008,
.data = {
{ 0x0400, 0x610b58 },
{ 0x0404, 0x610bdc },
{ 0x0420, 0x610828 },
{}
}
};
const struct nv50_disp_mthd_list
nv50_disp_core_mthd_sor = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0600, 0x610b70 },
{}
}
};
const struct nv50_disp_mthd_list
nv50_disp_core_mthd_pior = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0700, 0x610b80 },
{}
}
};
static const struct nv50_disp_mthd_list
nv50_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000540,
.data = {
{ 0x0800, 0x610ad8 },
{ 0x0804, 0x610ad0 },
{ 0x0808, 0x610a48 },
{ 0x080c, 0x610a78 },
{ 0x0810, 0x610ac0 },
{ 0x0814, 0x610af8 },
{ 0x0818, 0x610b00 },
{ 0x081c, 0x610ae8 },
{ 0x0820, 0x610af0 },
{ 0x0824, 0x610b08 },
{ 0x0828, 0x610b10 },
{ 0x082c, 0x610a68 },
{ 0x0830, 0x610a60 },
{ 0x0834, 0x000000 },
{ 0x0838, 0x610a40 },
{ 0x0840, 0x610a24 },
{ 0x0844, 0x610a2c },
{ 0x0848, 0x610aa8 },
{ 0x084c, 0x610ab0 },
{ 0x0860, 0x610a84 },
{ 0x0864, 0x610a90 },
{ 0x0868, 0x610b18 },
{ 0x086c, 0x610b20 },
{ 0x0870, 0x610ac8 },
{ 0x0874, 0x610a38 },
{ 0x0880, 0x610a58 },
{ 0x0884, 0x610a9c },
{ 0x08a0, 0x610a70 },
{ 0x08a4, 0x610a50 },
{ 0x08a8, 0x610ae0 },
{ 0x08c0, 0x610b28 },
{ 0x08c4, 0x610b30 },
{ 0x08c8, 0x610b40 },
{ 0x08d4, 0x610b38 },
{ 0x08d8, 0x610b48 },
{ 0x08dc, 0x610b50 },
{ 0x0900, 0x610a18 },
{ 0x0904, 0x610ab8 },
{}
}
};
static const struct nv50_disp_chan_mthd
nv50_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &nv50_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &nv50_disp_core_mthd_head },
{}
}
};
static void
nv50_disp_core_fini(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
/* deactivate channel */
nvkm_mask(device, 0x610200, 0x00000010, 0x00000000);
nvkm_mask(device, 0x610200, 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "core fini: %08x\n",
nvkm_rd32(device, 0x610200));
}
chan->suspend_put = nvkm_rd32(device, 0x640000);
}
static int
nv50_disp_core_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
/* attempt to unstick channel from some unknown state */
if ((nvkm_rd32(device, 0x610200) & 0x009f0000) == 0x00020000)
nvkm_mask(device, 0x610200, 0x00800000, 0x00800000);
if ((nvkm_rd32(device, 0x610200) & 0x003f0000) == 0x00030000)
nvkm_mask(device, 0x610200, 0x00600000, 0x00600000);
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x610204, chan->push);
nvkm_wr32(device, 0x610208, 0x00010000);
nvkm_wr32(device, 0x61020c, 0x00000000);
nvkm_mask(device, 0x610200, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000, chan->suspend_put);
nvkm_wr32(device, 0x610200, 0x01000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "core init: %08x\n",
nvkm_rd32(device, 0x610200));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
nv50_disp_core_func = {
.init = nv50_disp_core_init,
.fini = nv50_disp_core_fini,
.intr = nv50_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = nv50_disp_dmac_bind,
};
int
nv50_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_core_new_(&nv50_disp_core_func, &nv50_disp_core_mthd,
disp, 0, oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
int
gf119_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&gf119_disp_pioc_func, disp, 13, 13,
oclass, argv, argc, pobject);
}
/*
* Copyright 2016 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
int
gp102_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&gf119_disp_pioc_func, disp, 13, 17,
oclass, argv, argc, pobject);
}
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "channv50.h"
#include <subdev/timer.h>
static int
gv100_disp_curs_idle(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 soff = (chan->chid.ctrl - 1) * 0x04;
nvkm_msec(device, 2000,
u32 stat = nvkm_rd32(device, 0x610664 + soff);
if ((stat & 0x00070000) == 0x00040000)
return 0;
);
return -EBUSY;
}
static void
gv100_disp_curs_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 mask = 0x00010000 << chan->head;
const u32 data = en ? mask : 0;
nvkm_mask(device, 0x611dac, mask, data);
}
static void
gv100_disp_curs_fini(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 hoff = chan->chid.ctrl * 4;
nvkm_mask(device, 0x6104e0 + hoff, 0x00000010, 0x00000010);
gv100_disp_curs_idle(chan);
nvkm_mask(device, 0x6104e0 + hoff, 0x00000001, 0x00000000);
}
static int
gv100_disp_curs_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
nvkm_wr32(device, 0x6104e0 + chan->chid.ctrl * 4, 0x00000001);
return gv100_disp_curs_idle(chan);
}
static const struct nv50_disp_chan_func
gv100_disp_curs = {
.init = gv100_disp_curs_init,
.fini = gv100_disp_curs_fini,
.intr = gv100_disp_curs_intr,
.user = gv100_disp_chan_user,
};
int
gv100_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&gv100_disp_curs, disp, 73, 73,
oclass, argv, argc, pobject);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include "head.h"
#include <core/client.h>
#include <nvif/cl507a.h>
#include <nvif/unpack.h>
int
nv50_disp_curs_new_(const struct nv50_disp_chan_func *func,
struct nv50_disp *disp, int ctrl, int user,
const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
union {
struct nv50_disp_cursor_v0 v0;
} *args = argv;
struct nvkm_object *parent = oclass->parent;
int head, ret = -ENOSYS;
nvif_ioctl(parent, "create disp cursor size %d\n", argc);
if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp cursor vers %d head %d\n",
args->v0.version, args->v0.head);
if (!nvkm_head_find(&disp->base, args->v0.head))
return -EINVAL;
head = args->v0.head;
} else
return ret;
return nv50_disp_chan_new_(func, NULL, disp, ctrl + head, user + head,
head, oclass, pobject);
}
int
nv50_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
return nv50_disp_curs_new_(&nv50_disp_pioc_func, disp, 7, 7,
oclass, argv, argc, pobject);
}
/*
* Copyright 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ior.h"
static void
gf119_dac_clock(struct nvkm_ior *dac)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
nvkm_mask(device, 0x612280 + doff, 0x07070707, 0x00000000);
}
static void
gf119_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 coff = (state == &dac->asy) * 0x20000 + dac->id * 0x20;
u32 ctrl = nvkm_rd32(device, 0x640180 + coff);
state->proto_evo = (ctrl & 0x00000f00) >> 8;
switch (state->proto_evo) {
case 0: state->proto = CRT; break;
default:
state->proto = UNKNOWN;
break;
}
state->head = ctrl & 0x0000000f;
}
static const struct nvkm_ior_func
gf119_dac = {
.state = gf119_dac_state,
.power = nv50_dac_power,
.sense = nv50_dac_sense,
.clock = gf119_dac_clock,
};
int
gf119_dac_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&gf119_dac, disp, DAC, id);
}
int
gf119_dac_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = (nvkm_rd32(device, 0x612004) & 0x000000f0) >> 4;
return 4;
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "ior.h"
#include <subdev/timer.h>
static void
nv50_dac_clock(struct nvkm_ior *dac)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
nvkm_mask(device, 0x614280 + doff, 0x07070707, 0x00000000);
}
int
nv50_dac_sense(struct nvkm_ior *dac, u32 loadval)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
dac->func->power(dac, false, true, false, false, false);
nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval);
mdelay(9);
udelay(500);
loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000);
dac->func->power(dac, false, false, false, false, false);
if (!(loadval & 0x80000000))
return -ETIMEDOUT;
return (loadval & 0x38000000) >> 27;
}
static void
nv50_dac_power_wait(struct nvkm_device *device, const u32 doff)
{
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
break;
);
}
void
nv50_dac_power(struct nvkm_ior *dac, bool normal, bool pu,
bool data, bool vsync, bool hsync)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
const u32 shift = normal ? 0 : 16;
const u32 state = 0x80000000 | (0x00000040 * ! pu |
0x00000010 * ! data |
0x00000004 * ! vsync |
0x00000001 * ! hsync) << shift;
const u32 field = 0xc0000000 | (0x00000055 << shift);
nv50_dac_power_wait(device, doff);
nvkm_mask(device, 0x61a004 + doff, field, state);
nv50_dac_power_wait(device, doff);
}
static void
nv50_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state)
{
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 coff = dac->id * 8 + (state == &dac->arm) * 4;
u32 ctrl = nvkm_rd32(device, 0x610b58 + coff);
state->proto_evo = (ctrl & 0x00000f00) >> 8;
switch (state->proto_evo) {
case 0: state->proto = CRT; break;
default:
state->proto = UNKNOWN;
break;
}
state->head = ctrl & 0x00000003;
}
static const struct nvkm_ior_func
nv50_dac = {
.state = nv50_dac_state,
.power = nv50_dac_power,
.sense = nv50_dac_sense,
.clock = nv50_dac_clock,
};
int
nv50_dac_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&nv50_dac, disp, DAC, id);
}
int
nv50_dac_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = (nvkm_rd32(device, 0x610184) & 0x00700000) >> 20;
return 3;
}
/*
* Copyright 2016 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "channv50.h"
#include <subdev/timer.h>
static int
gp102_disp_dmac_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x611494 + (ctrl * 0x0010), chan->push);
nvkm_wr32(device, 0x611498 + (ctrl * 0x0010), 0x00010000);
nvkm_wr32(device, 0x61149c + (ctrl * 0x0010), 0x00000001);
nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), chan->suspend_put);
nvkm_wr32(device, 0x610490 + (ctrl * 0x0010), 0x00000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "ch %d init: %08x\n", user,
nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
gp102_disp_dmac_func = {
.init = gp102_disp_dmac_init,
.fini = gf119_disp_dmac_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};
/*
* Copyright 2018 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "channv50.h"
#include <core/ramht.h>
#include <subdev/timer.h>
static int
gv100_disp_dmac_idle(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 soff = (chan->chid.ctrl - 1) * 0x04;
nvkm_msec(device, 2000,
u32 stat = nvkm_rd32(device, 0x610664 + soff);
if ((stat & 0x000f0000) == 0x00040000)
return 0;
);
return -EBUSY;
}
int
gv100_disp_dmac_bind(struct nv50_disp_chan *chan,
struct nvkm_object *object, u32 handle)
{
return nvkm_ramht_insert(chan->disp->ramht, object,
chan->chid.user, -9, handle,
chan->chid.user << 25 | 0x00000040);
}
void
gv100_disp_dmac_fini(struct nv50_disp_chan *chan)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 uoff = (chan->chid.ctrl - 1) * 0x1000;
const u32 coff = chan->chid.ctrl * 0x04;
nvkm_mask(device, 0x6104e0 + coff, 0x00000010, 0x00000000);
gv100_disp_dmac_idle(chan);
nvkm_mask(device, 0x6104e0 + coff, 0x00000002, 0x00000000);
chan->suspend_put = nvkm_rd32(device, 0x690000 + uoff);
}
int
gv100_disp_dmac_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
const u32 uoff = (chan->chid.ctrl - 1) * 0x1000;
const u32 poff = chan->chid.ctrl * 0x10;
const u32 coff = chan->chid.ctrl * 0x04;
nvkm_wr32(device, 0x610b24 + poff, lower_32_bits(chan->push));
nvkm_wr32(device, 0x610b20 + poff, upper_32_bits(chan->push));
nvkm_wr32(device, 0x610b28 + poff, 0x00000001);
nvkm_wr32(device, 0x610b2c + poff, 0x00000040);
nvkm_mask(device, 0x6104e0 + coff, 0x00000010, 0x00000010);
nvkm_wr32(device, 0x690000 + uoff, chan->suspend_put);
nvkm_wr32(device, 0x6104e0 + coff, 0x00000013);
return gv100_disp_dmac_idle(chan);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include <core/client.h>
#include <core/ramht.h>
#include <subdev/fb.h>
#include <subdev/mmu.h>
#include <subdev/timer.h>
#include <engine/dma.h>
int
nv50_disp_dmac_new_(const struct nv50_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd,
struct nv50_disp *disp, int chid, int head, u64 push,
const struct nvkm_oclass *oclass,
struct nvkm_object **pobject)
{
struct nvkm_client *client = oclass->client;
struct nv50_disp_chan *chan;
int ret;
ret = nv50_disp_chan_new_(func, mthd, disp, chid, chid, head, oclass,
pobject);
chan = nv50_disp_chan(*pobject);
if (ret)
return ret;
chan->memory = nvkm_umem_search(client, push);
if (IS_ERR(chan->memory))
return PTR_ERR(chan->memory);
if (nvkm_memory_size(chan->memory) < 0x1000)
return -EINVAL;
switch (nvkm_memory_target(chan->memory)) {
case NVKM_MEM_TARGET_VRAM: chan->push = 0x00000001; break;
case NVKM_MEM_TARGET_NCOH: chan->push = 0x00000002; break;
case NVKM_MEM_TARGET_HOST: chan->push = 0x00000003; break;
default:
return -EINVAL;
}
chan->push |= nvkm_memory_addr(chan->memory) >> 8;
return 0;
}
int
nv50_disp_dmac_bind(struct nv50_disp_chan *chan,
struct nvkm_object *object, u32 handle)
{
return nvkm_ramht_insert(chan->disp->ramht, object,
chan->chid.user, -10, handle,
chan->chid.user << 28 |
chan->chid.user);
}
static void
nv50_disp_dmac_fini(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* deactivate channel */
nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00001010, 0x00001000);
nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "ch %d fini timeout, %08x\n", user,
nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
}
chan->suspend_put = nvkm_rd32(device, 0x640000 + (ctrl * 0x1000));
}
static int
nv50_disp_dmac_init(struct nv50_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
int ctrl = chan->chid.ctrl;
int user = chan->chid.user;
/* initialise channel for dma command submission */
nvkm_wr32(device, 0x610204 + (ctrl * 0x0010), chan->push);
nvkm_wr32(device, 0x610208 + (ctrl * 0x0010), 0x00010000);
nvkm_wr32(device, 0x61020c + (ctrl * 0x0010), ctrl);
nvkm_mask(device, 0x610200 + (ctrl * 0x0010), 0x00000010, 0x00000010);
nvkm_wr32(device, 0x640000 + (ctrl * 0x1000), chan->suspend_put);
nvkm_wr32(device, 0x610200 + (ctrl * 0x0010), 0x00000013);
/* wait for it to go inactive */
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610200 + (ctrl * 0x10)) & 0x80000000))
break;
) < 0) {
nvkm_error(subdev, "ch %d init timeout, %08x\n", user,
nvkm_rd32(device, 0x610200 + (ctrl * 0x10)));
return -EBUSY;
}
return 0;
}
const struct nv50_disp_chan_func
nv50_disp_dmac_func = {
.init = nv50_disp_dmac_init,
.fini = nv50_disp_dmac_fini,
.intr = nv50_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = nv50_disp_dmac_bind,
};
/* SPDX-License-Identifier: MIT */ /* SPDX-License-Identifier: MIT */
#ifndef __NVKM_DISP_DP_H__ #ifndef __NVKM_DISP_DP_H__
#define __NVKM_DISP_DP_H__ #define __NVKM_DISP_DP_H__
#define nvkm_dp(p) container_of((p), struct nvkm_dp, outp)
#include "outp.h" #include "outp.h"
#include <core/notify.h>
#include <subdev/bios.h>
#include <subdev/bios/dp.h>
struct nvkm_dp {
struct nvkm_outp outp;
struct nvbios_dpout info;
u8 version;
struct nvkm_i2c_aux *aux;
struct nvkm_notify hpd;
bool present;
u8 lttpr[6];
u8 lttprs;
u8 dpcd[16];
struct {
int dpcd; /* -1, or index into SUPPORTED_LINK_RATES table */
u32 rate;
} rate[8];
int rates;
int links;
struct mutex mutex;
struct {
atomic_t done;
bool mst;
} lt;
};
int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *, int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *,
struct nvkm_outp **); struct nvkm_outp **);
void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);
......
...@@ -21,28 +21,307 @@ ...@@ -21,28 +21,307 @@
* *
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include "nv50.h" #include "priv.h"
#include "chan.h"
#include "hdmi.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func #include <nvif/class.h>
void
g84_sor_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet,
u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 ctrl = 0x40000000 * enable |
0x1f000000 /* ??? */ |
max_ac_packet << 16 |
rekey;
const u32 hoff = head * 0x800;
struct packed_hdmi_infoframe avi_infoframe;
struct packed_hdmi_infoframe vendor_infoframe;
pack_hdmi_infoframe(&avi_infoframe, avi, avi_size);
pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size);
if (!(ctrl & 0x40000000)) {
nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x61653c + hoff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x616528 + hoff, avi_infoframe.header);
nvkm_wr32(device, 0x61652c + hoff, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x616530 + hoff, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x616534 + hoff, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x616538 + hoff, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001);
}
/* Audio InfoFrame */
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x616508 + hoff, 0x000a0184);
nvkm_wr32(device, 0x61650c + hoff, 0x00000071);
nvkm_wr32(device, 0x616510 + hoff, 0x00000000);
nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001);
/* Vendor InfoFrame */
nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000);
if (vendor_size) {
nvkm_wr32(device, 0x616544 + hoff, vendor_infoframe.header);
nvkm_wr32(device, 0x616548 + hoff, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x61654c + hoff, vendor_infoframe.subpack0_high);
/* Is there a second (or up to fourth?) set of subpack registers here? */
/* nvkm_wr32(device, 0x616550 + hoff, vendor_infoframe->subpack1_low); */
/* nvkm_wr32(device, 0x616554 + hoff, vendor_infoframe->subpack1_high); */
nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001);
}
nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
nvkm_mask(device, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
/* ??? */
nvkm_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
nvkm_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
nvkm_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
/* HDMI_CTRL */
nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
}
static const struct nvkm_ior_func
g84_sor = {
.state = nv50_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
.hdmi = {
.ctrl = g84_sor_hdmi_ctrl,
},
};
int
g84_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&g84_sor, disp, SOR, id, false);
}
static const struct nvkm_disp_mthd_list
g84_disp_ovly_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x6109a0 },
{ 0x0088, 0x6109c0 },
{ 0x008c, 0x6109c8 },
{ 0x0090, 0x6109b4 },
{ 0x0094, 0x610970 },
{ 0x00a0, 0x610998 },
{ 0x00a4, 0x610964 },
{ 0x00c0, 0x610958 },
{ 0x00e0, 0x6109a8 },
{ 0x00e4, 0x6109d0 },
{ 0x00e8, 0x6109d8 },
{ 0x0100, 0x61094c },
{ 0x0104, 0x610984 },
{ 0x0108, 0x61098c },
{ 0x0800, 0x6109f8 },
{ 0x0808, 0x610a08 },
{ 0x080c, 0x610a10 },
{ 0x0810, 0x610a00 },
{}
}
};
static const struct nvkm_disp_chan_mthd
g84_disp_ovly_mthd = {
.name = "Overlay",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &g84_disp_ovly_mthd_base },
{}
}
};
const struct nvkm_disp_chan_user
g84_disp_ovly = {
.func = &nv50_disp_dmac_func,
.ctrl = 3,
.user = 3,
.mthd = &g84_disp_ovly_mthd,
};
static const struct nvkm_disp_mthd_list
g84_disp_base_mthd_base = {
.mthd = 0x0000,
.addr = 0x000000,
.data = {
{ 0x0080, 0x000000 },
{ 0x0084, 0x0008c4 },
{ 0x0088, 0x0008d0 },
{ 0x008c, 0x0008dc },
{ 0x0090, 0x0008e4 },
{ 0x0094, 0x610884 },
{ 0x00a0, 0x6108a0 },
{ 0x00a4, 0x610878 },
{ 0x00c0, 0x61086c },
{ 0x00c4, 0x610800 },
{ 0x00c8, 0x61080c },
{ 0x00cc, 0x610818 },
{ 0x00e0, 0x610858 },
{ 0x00e4, 0x610860 },
{ 0x00e8, 0x6108ac },
{ 0x00ec, 0x6108b4 },
{ 0x00fc, 0x610824 },
{ 0x0100, 0x610894 },
{ 0x0104, 0x61082c },
{ 0x0110, 0x6108bc },
{ 0x0114, 0x61088c },
{}
}
};
static const struct nvkm_disp_chan_mthd
g84_disp_base_mthd = {
.name = "Base",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &g84_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_base_mthd_image },
{}
}
};
const struct nvkm_disp_chan_user
g84_disp_base = {
.func = &nv50_disp_dmac_func,
.ctrl = 1,
.user = 1,
.mthd = &g84_disp_base_mthd,
};
const struct nvkm_disp_mthd_list
g84_disp_core_mthd_dac = {
.mthd = 0x0080,
.addr = 0x000008,
.data = {
{ 0x0400, 0x610b58 },
{ 0x0404, 0x610bdc },
{ 0x0420, 0x610bc4 },
{}
}
};
const struct nvkm_disp_mthd_list
g84_disp_core_mthd_head = {
.mthd = 0x0400,
.addr = 0x000540,
.data = {
{ 0x0800, 0x610ad8 },
{ 0x0804, 0x610ad0 },
{ 0x0808, 0x610a48 },
{ 0x080c, 0x610a78 },
{ 0x0810, 0x610ac0 },
{ 0x0814, 0x610af8 },
{ 0x0818, 0x610b00 },
{ 0x081c, 0x610ae8 },
{ 0x0820, 0x610af0 },
{ 0x0824, 0x610b08 },
{ 0x0828, 0x610b10 },
{ 0x082c, 0x610a68 },
{ 0x0830, 0x610a60 },
{ 0x0834, 0x000000 },
{ 0x0838, 0x610a40 },
{ 0x0840, 0x610a24 },
{ 0x0844, 0x610a2c },
{ 0x0848, 0x610aa8 },
{ 0x084c, 0x610ab0 },
{ 0x085c, 0x610c5c },
{ 0x0860, 0x610a84 },
{ 0x0864, 0x610a90 },
{ 0x0868, 0x610b18 },
{ 0x086c, 0x610b20 },
{ 0x0870, 0x610ac8 },
{ 0x0874, 0x610a38 },
{ 0x0878, 0x610c50 },
{ 0x0880, 0x610a58 },
{ 0x0884, 0x610a9c },
{ 0x089c, 0x610c68 },
{ 0x08a0, 0x610a70 },
{ 0x08a4, 0x610a50 },
{ 0x08a8, 0x610ae0 },
{ 0x08c0, 0x610b28 },
{ 0x08c4, 0x610b30 },
{ 0x08c8, 0x610b40 },
{ 0x08d4, 0x610b38 },
{ 0x08d8, 0x610b48 },
{ 0x08dc, 0x610b50 },
{ 0x0900, 0x610a18 },
{ 0x0904, 0x610ab8 },
{ 0x0910, 0x610c70 },
{ 0x0914, 0x610c78 },
{}
}
};
const struct nvkm_disp_chan_mthd
g84_disp_core_mthd = {
.name = "Core",
.addr = 0x000000,
.prev = 0x000004,
.data = {
{ "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &g84_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &g84_disp_core_mthd_head },
{}
}
};
const struct nvkm_disp_chan_user
g84_disp_core = {
.func = &nv50_disp_core_func,
.ctrl = 0,
.user = 0,
.mthd = &g84_disp_core_mthd,
};
static const struct nvkm_disp_func
g84_disp = { g84_disp = {
.oneinit = nv50_disp_oneinit,
.init = nv50_disp_init, .init = nv50_disp_init,
.fini = nv50_disp_fini, .fini = nv50_disp_fini,
.intr = nv50_disp_intr, .intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super, .super = nv50_disp_super,
.root = &g84_disp_root_oclass, .uevent = &nv50_disp_chan_uevent,
.head = { .cnt = nv50_head_cnt, .new = nv50_head_new }, .head = { .cnt = nv50_head_cnt, .new = nv50_head_new },
.dac = { .cnt = nv50_dac_cnt, .new = nv50_dac_new }, .dac = { .cnt = nv50_dac_cnt, .new = nv50_dac_new },
.sor = { .cnt = nv50_sor_cnt, .new = g84_sor_new }, .sor = { .cnt = nv50_sor_cnt, .new = g84_sor_new },
.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new }, .pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
.root = { 0,0,G82_DISP },
.user = {
{{0,0,G82_DISP_CURSOR }, nvkm_disp_chan_new, &nv50_disp_curs },
{{0,0,G82_DISP_OVERLAY }, nvkm_disp_chan_new, &nv50_disp_oimm },
{{0,0,G82_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, & g84_disp_base },
{{0,0,G82_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, & g84_disp_core },
{{0,0,G82_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, & g84_disp_ovly },
{}
},
}; };
int int
g84_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, g84_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp) struct nvkm_disp **pdisp)
{ {
return nv50_disp_new_(&g84_disp, device, type, inst, pdisp); return nvkm_disp_new_(&g84_disp, device, type, inst, pdisp);
} }
...@@ -19,29 +19,135 @@ ...@@ -19,29 +19,135 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "nv50.h" #include "priv.h"
#include "chan.h"
#include "head.h" #include "head.h"
#include "ior.h" #include "ior.h"
#include "channv50.h"
#include "rootnv50.h"
static const struct nv50_disp_func #include <subdev/timer.h>
#include <nvif/class.h>
static int
ga102_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;
switch (sor->dp.bw) {
case 0x06: clksor |= 0x00000000; break;
case 0x0a: clksor |= 0x00040000; break;
case 0x14: clksor |= 0x00080000; break;
case 0x1e: clksor |= 0x000c0000; break;
case 0x08: clksor |= 0x00100000; break;
case 0x09: clksor |= 0x00140000; break;
case 0x0c: clksor |= 0x00180000; break;
case 0x10: clksor |= 0x001c0000; break;
default:
WARN_ON(1);
return -EINVAL;
}
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
ga102_sor_dp = {
.lanes = { 0, 1, 2, 3 },
.links = ga102_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 void
ga102_sor_clock(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
u32 div2 = 0;
if (sor->asy.proto == TMDS) {
if (sor->tmds.high_speed)
div2 = 1;
}
nvkm_wr32(device, 0x00ec08 + (sor->id * 0x10), 0x00000000);
nvkm_wr32(device, 0x00ec04 + (sor->id * 0x10), div2);
}
static const struct nvkm_ior_func
ga102_sor = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
},
.state = gv100_sor_state,
.power = nv50_sor_power,
.clock = ga102_sor_clock,
.hdmi = {
.ctrl = gv100_sor_hdmi_ctrl,
.scdc = gm200_sor_hdmi_scdc,
},
.dp = &ga102_sor_dp,
.hda = &gv100_sor_hda,
};
static int
ga102_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_(&ga102_sor, disp, SOR, id, hda & BIT(id));
}
static const struct nvkm_disp_func
ga102_disp = { ga102_disp = {
.oneinit = nv50_disp_oneinit,
.init = tu102_disp_init, .init = tu102_disp_init,
.fini = gv100_disp_fini, .fini = gv100_disp_fini,
.intr = gv100_disp_intr, .intr = gv100_disp_intr,
.uevent = &gv100_disp_chan_uevent,
.super = gv100_disp_super, .super = gv100_disp_super,
.root = &ga102_disp_root_oclass, .uevent = &gv100_disp_chan_uevent,
.wndw = { .cnt = gv100_disp_wndw_cnt }, .wndw = { .cnt = gv100_disp_wndw_cnt },
.head = { .cnt = gv100_head_cnt, .new = gv100_head_new }, .head = { .cnt = gv100_head_cnt, .new = gv100_head_new },
.sor = { .cnt = gv100_sor_cnt, .new = ga102_sor_new }, .sor = { .cnt = gv100_sor_cnt, .new = ga102_sor_new },
.ramht_size = 0x2000, .ramht_size = 0x2000,
.root = { 0, 0,GA102_DISP },
.user = {
{{-1,-1,GV100_DISP_CAPS }, gv100_disp_caps_new },
{{ 0, 0,GA102_DISP_CURSOR }, nvkm_disp_chan_new, &gv100_disp_curs },
{{ 0, 0,GA102_DISP_WINDOW_IMM_CHANNEL_DMA}, nvkm_disp_wndw_new, &gv100_disp_wimm },
{{ 0, 0,GA102_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gv100_disp_core },
{{ 0, 0,GA102_DISP_WINDOW_CHANNEL_DMA }, nvkm_disp_wndw_new, &gv100_disp_wndw },
{}
},
}; };
int int
ga102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, ga102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp) struct nvkm_disp **pdisp)
{ {
return nv50_disp_new_(&ga102_disp, device, type, inst, pdisp); return nvkm_disp_new_(&ga102_disp, device, type, inst, pdisp);
} }
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2020 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "ior.h"
void
gv100_hda_device_entry(struct nvkm_ior *ior, int head)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 hoff = 0x800 * head;
nvkm_mask(device, 0x616528 + hoff, 0x00000070, head << 4);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment