1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00

drm/nouveau-misc: display patches.

These are just some precursor and cleanup display patches from Ben,
 tested by Lyude.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmLgeCwACgkQDHTzWXnE
 hr6zrA//TQ994TaVlsIjNofD/ZqSgDS2P3SQPlLdwhMiNAoJZH5nDlw/Ec3eBYYb
 URqRZidsUCrSDDWRjaLnvMFCR35RuoMh0iadmjT2Q4ceuwPnbRIdobJIL9/sy1Ra
 XLgV4DLNAYSI9qwvj/1UatHL9fXhP4K9CtlGqeLpGylDpNOwQkeJqgpN2gyw1uMp
 xPEaCnI3RBzFbAt5aWkw3uWsfObYLFT9DTkHSaCmjq1QeMf/Cc7z/oLJi5bGvela
 226MYdAWTk+gpgR41B3CyGdO7rZSB16cq8ZY5Do8+naD8QmISO48urZ3+Y5RE05r
 JQnY5YY+XaGW/f65RzuO1vubUdU2dRlDdMhJ+sU51iCD8cKCTwqrdHVaHyqhdq9U
 +LPXhlV0rCUGS3ZTAA1ZUM8ngU4dNKnRLV1XEqtJxwdIoydCroq2xgn1GBFZ4SBe
 kuSDHNdPcN8VosmQMAGmRYrFadCqbw9K2TLstfJQLlqWZHAWVVmhnM3Fzu25qIl+
 lGwLTHMxc5UjO9OXu+7EZ17NEduNx30jPBZBOzmwLbOWECCLaTD9ob8ha+Rt/h47
 gtSQGP6BFkfTC5kK0yNfXRC2GA+iVdloSSZa/g/P+1qr78tUMEL7M2o2lw4OcTyP
 RizKQxVONgEIexPPFHdEDKA6RrO2JTUPjQS+PTsqsYIbOXmCy/w=
 =pYN/
 -----END PGP SIGNATURE-----

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: Dave Airlie <airlied@redhat.com>

From: Dave Airlie <airlied@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/CAPM=9ty0R37q0mohBr_CegpYLXK2=fAH54QfAsMhHfPygTsdQA@mail.gmail.com
This commit is contained in:
Dave Airlie 2022-07-27 10:11:59 +10:00
commit 2bc7ea71a7
158 changed files with 6411 additions and 8870 deletions

View file

@ -21,8 +21,7 @@
*/
#include "base.h"
#include <nvif/cl507c.h>
#include <nvif/event.h>
#include <nvif/if0014.h>
#include <nvif/push507c.h>
#include <nvif/timer.h>
@ -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 nv50_wndw **pwndw)
{
struct nv50_disp_base_channel_dma_v0 args = {
.head = head,
struct nvif_disp_chan_v0 args = {
.id = head,
};
struct nouveau_display *disp = nouveau_display(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,
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->sema = NV50_DISP_BASE_SEM0(wndw->id);
wndw->data = 0x00000000;

View file

@ -22,7 +22,7 @@
#include "core.h"
#include "head.h"
#include <nvif/cl507d.h>
#include <nvif/if0014.h>
#include <nvif/push507c.h>
#include <nvif/timer.h>
@ -157,7 +157,7 @@ int
core507d_new_(const struct nv50_core_func *func, struct nouveau_drm *drm,
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_core *core;
int ret;

View file

@ -23,7 +23,7 @@
#include "core.h"
#include "head.h"
#include <nvif/cl507a.h>
#include <nvif/if0014.h>
#include <nvif/timer.h>
#include <nvhw/class/cl507a.h>
@ -150,8 +150,8 @@ curs507a_new_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
int head, s32 oclass, u32 interlock_data,
struct nv50_wndw **pwndw)
{
struct nv50_disp_cursor_v0 args = {
.head = head,
struct nvif_disp_chan_v0 args = {
.id = head,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_wndw *wndw;

View file

@ -48,8 +48,8 @@
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/cl5070.h>
#include <nvif/cl507d.h>
#include <nvif/event.h>
#include <nvif/if0014.h>
#include <nvif/timer.h>
#include <nvhw/class/cl507c.h>
@ -231,7 +231,7 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
struct nv50_dmac *dmac)
{
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;
int ret;
@ -529,24 +529,15 @@ static enum drm_connector_status
nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev);
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,
};
u32 loadval;
int ret;
args.load.data = nouveau_drm(encoder->dev)->vbios.dactestval;
if (args.load.data == 0)
args.load.data = 340;
loadval = nouveau_drm(encoder->dev)->vbios.dactestval;
if (loadval == 0)
loadval = 340;
ret = nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
if (ret || !args.load.load)
ret = nvif_outp_load_detect(&nv_encoder->outp, loadval);
if (ret <= 0)
return connector_status_disconnected;
return connector_status_connected;
@ -563,6 +554,10 @@ nv50_dac_help = {
static void
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);
kfree(encoder);
}
@ -576,6 +571,7 @@ static int
nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
{
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_bus *bus;
struct nouveau_encoder *nv_encoder;
@ -599,7 +595,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
drm_encoder_helper_add(encoder, &nv50_dac_help);
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
nv50_sor_destroy(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
nvif_outp_dtor(&nv_encoder->outp);
nv50_mstm_del(&nv_encoder->dp.mstm);
drm_encoder_cleanup(encoder);
@ -1918,7 +1917,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
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 = {
static void
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);
kfree(encoder);
}
@ -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);
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);
}
/******************************************************************************

View file

@ -21,14 +21,14 @@
*/
#include "oimm.h"
#include <nvif/cl507b.h>
#include <nvif/if0014.h>
static int
oimm507b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
s32 oclass, struct nv50_wndw *wndw)
{
struct nv50_disp_overlay_v0 args = {
.head = wndw->id,
struct nvif_disp_chan_v0 args = {
.id = wndw->id,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
int ret;

View file

@ -26,8 +26,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <nvif/cl507e.h>
#include <nvif/event.h>
#include <nvif/if0014.h>
#include <nvif/push507c.h>
#include <nvhw/class/cl507e.h>
@ -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 nv50_wndw **pwndw)
{
struct nv50_disp_overlay_channel_dma_v0 args = {
.head = head,
struct nvif_disp_chan_v0 args = {
.id = head,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_wndw *wndw;
@ -169,16 +168,6 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
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->sema = NV50_DISP_OVLY_SEM0(wndw->id);
wndw->data = 0x00000000;

View file

@ -23,7 +23,7 @@
#include "atom.h"
#include "wndw.h"
#include <nvif/clc37b.h>
#include <nvif/if0014.h>
#include <nvif/pushc37b.h>
#include <nvhw/class/clc37b.h>
@ -68,9 +68,8 @@ static int
wimmc37b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
s32 oclass, struct nv50_wndw *wndw)
{
struct nvc37b_window_imm_channel_dma_v0 args = {
.pushbuf = 0xb0007b00 | wndw->id,
.index = wndw->id,
struct nvif_disp_chan_v0 args = {
.id = wndw->id,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
int ret;

View file

@ -644,7 +644,6 @@ nv50_wndw_destroy(struct drm_plane *plane)
nv50_wndw_ctxdma_del(ctxdma);
}
nvif_notify_dtor(&wndw->notify);
nv50_dmac_destroy(&wndw->wimm);
nv50_dmac_destroy(&wndw->wndw);
@ -688,12 +687,6 @@ nv50_wndw = {
.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[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID,
@ -747,8 +740,6 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
return ret;
}
wndw->notify.func = nv50_wndw_notify;
if (wndw->func->blend_set) {
ret = drm_plane_create_zpos_property(&wndw->plane,
nv50_wndw_zpos_default(&wndw->plane), 0, 254);

View file

@ -5,8 +5,6 @@
#include "atom.h"
#include "lut.h"
#include <nvif/notify.h>
struct nv50_wndw_ctxdma {
struct list_head head;
struct nvif_object object;
@ -30,7 +28,6 @@ struct nv50_wndw {
struct nv50_dmac wndw;
struct nv50_dmac wimm;
struct nvif_notify notify;
u16 ntfy;
u16 sema;
u32 data;

View file

@ -26,7 +26,7 @@
#include <drm/drm_plane_helper.h>
#include <nouveau_bo.h>
#include <nvif/clc37e.h>
#include <nvif/if0014.h>
#include <nvif/pushc37b.h>
#include <nvhw/class/clc37e.h>
@ -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,
struct nv50_wndw **pwndw)
{
struct nvc37e_window_channel_dma_v0 args = {
.pushbuf = 0xb0007e00 | index,
.index = index,
struct nvif_disp_chan_v0 args = {
.id = index,
};
struct nv50_disp *disp = nv50_disp(drm->dev);
struct nv50_wndw *wndw;

View file

@ -26,7 +26,6 @@
#include <drm/drm_plane_helper.h>
#include <nouveau_bo.h>
#include <nvif/clc37e.h>
#include <nvif/pushc37b.h>
#include <nvhw/class/clc57e.h>

View file

@ -30,7 +30,6 @@ struct nv50_disp_mthd_v1 {
__u8 version;
#define NV50_DISP_MTHD_V1_ACQUIRE 0x01
#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_HDMI_PWR 0x22
#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
@ -50,13 +49,6 @@ struct nv50_disp_acquire_v0 {
__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 {
__u8 version;
__u8 pad01[7];

View file

@ -1,12 +0,0 @@
/* 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

View file

@ -1,12 +0,0 @@
/* 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

View file

@ -1,13 +0,0 @@
/* 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

View file

@ -1,12 +0,0 @@
/* 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

View file

@ -1,13 +0,0 @@
/* 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

View file

@ -32,6 +32,11 @@
#define NVIF_CLASS_VMM_GM200 /* ifb00d.h */ 0x8000b00d
#define NVIF_CLASS_VMM_GP100 /* ifc00d.h */ 0x8000c00d
#define NVIF_CLASS_DISP /* if0010.h */ 0x80000010
#define NVIF_CLASS_CONN /* if0011.h */ 0x80000011
#define NVIF_CLASS_OUTP /* if0012.h */ 0x80000012
#define NVIF_CLASS_DISP_CHAN /* if0014.h */ 0x80000014
/* the below match nvidia-assigned (either in hw, or sw) class numbers */
#define NV_NULL_CLASS 0x00000030
@ -73,21 +78,21 @@
#define TURING_CHANNEL_GPFIFO_A /* clc36f.h */ 0x0000c46f
#define AMPERE_CHANNEL_GPFIFO_B /* clc36f.h */ 0x0000c76f
#define NV50_DISP /* cl5070.h */ 0x00005070
#define G82_DISP /* cl5070.h */ 0x00008270
#define GT200_DISP /* cl5070.h */ 0x00008370
#define GT214_DISP /* cl5070.h */ 0x00008570
#define GT206_DISP /* cl5070.h */ 0x00008870
#define GF110_DISP /* cl5070.h */ 0x00009070
#define GK104_DISP /* cl5070.h */ 0x00009170
#define GK110_DISP /* cl5070.h */ 0x00009270
#define GM107_DISP /* cl5070.h */ 0x00009470
#define GM200_DISP /* cl5070.h */ 0x00009570
#define GP100_DISP /* cl5070.h */ 0x00009770
#define GP102_DISP /* cl5070.h */ 0x00009870
#define GV100_DISP /* cl5070.h */ 0x0000c370
#define TU102_DISP /* cl5070.h */ 0x0000c570
#define GA102_DISP /* cl5070.h */ 0x0000c670
#define NV50_DISP /* if0010.h */ 0x00005070
#define G82_DISP /* if0010.h */ 0x00008270
#define GT200_DISP /* if0010.h */ 0x00008370
#define GT214_DISP /* if0010.h */ 0x00008570
#define GT206_DISP /* if0010.h */ 0x00008870
#define GF110_DISP /* if0010.h */ 0x00009070
#define GK104_DISP /* if0010.h */ 0x00009170
#define GK110_DISP /* if0010.h */ 0x00009270
#define GM107_DISP /* if0010.h */ 0x00009470
#define GM200_DISP /* if0010.h */ 0x00009570
#define GP100_DISP /* if0010.h */ 0x00009770
#define GP102_DISP /* if0010.h */ 0x00009870
#define GV100_DISP /* if0010.h */ 0x0000c370
#define TU102_DISP /* if0010.h */ 0x0000c570
#define GA102_DISP /* if0010.h */ 0x0000c670
#define GV100_DISP_CAPS 0x0000c373
@ -96,59 +101,59 @@
#define NV74_VP2 0x00007476
#define NV50_DISP_CURSOR /* cl507a.h */ 0x0000507a
#define G82_DISP_CURSOR /* cl507a.h */ 0x0000827a
#define GT214_DISP_CURSOR /* cl507a.h */ 0x0000857a
#define GF110_DISP_CURSOR /* cl507a.h */ 0x0000907a
#define GK104_DISP_CURSOR /* cl507a.h */ 0x0000917a
#define GV100_DISP_CURSOR /* cl507a.h */ 0x0000c37a
#define TU102_DISP_CURSOR /* cl507a.h */ 0x0000c57a
#define GA102_DISP_CURSOR /* cl507a.h */ 0x0000c67a
#define NV50_DISP_CURSOR /* if0014.h */ 0x0000507a
#define G82_DISP_CURSOR /* if0014.h */ 0x0000827a
#define GT214_DISP_CURSOR /* if0014.h */ 0x0000857a
#define GF110_DISP_CURSOR /* if0014.h */ 0x0000907a
#define GK104_DISP_CURSOR /* if0014.h */ 0x0000917a
#define GV100_DISP_CURSOR /* if0014.h */ 0x0000c37a
#define TU102_DISP_CURSOR /* if0014.h */ 0x0000c57a
#define GA102_DISP_CURSOR /* if0014.h */ 0x0000c67a
#define NV50_DISP_OVERLAY /* cl507b.h */ 0x0000507b
#define G82_DISP_OVERLAY /* cl507b.h */ 0x0000827b
#define GT214_DISP_OVERLAY /* cl507b.h */ 0x0000857b
#define GF110_DISP_OVERLAY /* cl507b.h */ 0x0000907b
#define GK104_DISP_OVERLAY /* cl507b.h */ 0x0000917b
#define NV50_DISP_OVERLAY /* if0014.h */ 0x0000507b
#define G82_DISP_OVERLAY /* if0014.h */ 0x0000827b
#define GT214_DISP_OVERLAY /* if0014.h */ 0x0000857b
#define GF110_DISP_OVERLAY /* if0014.h */ 0x0000907b
#define GK104_DISP_OVERLAY /* if0014.h */ 0x0000917b
#define GV100_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c37b
#define TU102_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c57b
#define GA102_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c67b
#define GV100_DISP_WINDOW_IMM_CHANNEL_DMA /* if0014.h */ 0x0000c37b
#define TU102_DISP_WINDOW_IMM_CHANNEL_DMA /* if0014.h */ 0x0000c57b
#define GA102_DISP_WINDOW_IMM_CHANNEL_DMA /* if0014.h */ 0x0000c67b
#define NV50_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000507c
#define G82_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000827c
#define GT200_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000837c
#define GT214_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000857c
#define GF110_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000907c
#define GK104_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000917c
#define GK110_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000927c
#define NV50_DISP_BASE_CHANNEL_DMA /* if0014.h */ 0x0000507c
#define G82_DISP_BASE_CHANNEL_DMA /* if0014.h */ 0x0000827c
#define GT200_DISP_BASE_CHANNEL_DMA /* if0014.h */ 0x0000837c
#define GT214_DISP_BASE_CHANNEL_DMA /* if0014.h */ 0x0000857c
#define GF110_DISP_BASE_CHANNEL_DMA /* if0014.h */ 0x0000907c
#define GK104_DISP_BASE_CHANNEL_DMA /* if0014.h */ 0x0000917c
#define GK110_DISP_BASE_CHANNEL_DMA /* if0014.h */ 0x0000927c
#define NV50_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000507d
#define G82_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000827d
#define GT200_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000837d
#define GT214_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000857d
#define GT206_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000887d
#define GF110_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000907d
#define GK104_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000917d
#define GK110_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000927d
#define GM107_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000947d
#define GM200_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000957d
#define GP100_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000977d
#define GP102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000987d
#define GV100_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c37d
#define TU102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c57d
#define GA102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c67d
#define NV50_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000507d
#define G82_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000827d
#define GT200_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000837d
#define GT214_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000857d
#define GT206_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000887d
#define GF110_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000907d
#define GK104_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000917d
#define GK110_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000927d
#define GM107_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000947d
#define GM200_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000957d
#define GP100_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000977d
#define GP102_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000987d
#define GV100_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000c37d
#define TU102_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000c57d
#define GA102_DISP_CORE_CHANNEL_DMA /* if0014.h */ 0x0000c67d
#define NV50_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000507e
#define G82_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000827e
#define GT200_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000837e
#define GT214_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000857e
#define GF110_DISP_OVERLAY_CONTROL_DMA /* cl507e.h */ 0x0000907e
#define GK104_DISP_OVERLAY_CONTROL_DMA /* cl507e.h */ 0x0000917e
#define NV50_DISP_OVERLAY_CHANNEL_DMA /* if0014.h */ 0x0000507e
#define G82_DISP_OVERLAY_CHANNEL_DMA /* if0014.h */ 0x0000827e
#define GT200_DISP_OVERLAY_CHANNEL_DMA /* if0014.h */ 0x0000837e
#define GT214_DISP_OVERLAY_CHANNEL_DMA /* if0014.h */ 0x0000857e
#define GF110_DISP_OVERLAY_CONTROL_DMA /* if0014.h */ 0x0000907e
#define GK104_DISP_OVERLAY_CONTROL_DMA /* if0014.h */ 0x0000917e
#define GV100_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c37e
#define TU102_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c57e
#define GA102_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c67e
#define GV100_DISP_WINDOW_CHANNEL_DMA /* if0014.h */ 0x0000c37e
#define TU102_DISP_WINDOW_CHANNEL_DMA /* if0014.h */ 0x0000c57e
#define GA102_DISP_WINDOW_CHANNEL_DMA /* if0014.h */ 0x0000c67e
#define NV50_TESLA 0x00005097
#define G82_TESLA 0x00008297

View file

@ -1,11 +0,0 @@
/* 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

View file

@ -1,13 +0,0 @@
/* 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

View file

@ -0,0 +1,18 @@
/* 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

View file

@ -5,6 +5,8 @@ struct nvif_device;
struct nvif_disp {
struct nvif_object object;
unsigned long conn_mask;
unsigned long outp_mask;
};
int nvif_disp_ctor(struct nvif_device *, const char *name, s32 oclass,

View file

@ -0,0 +1,13 @@
/* 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

View file

@ -0,0 +1,23 @@
/* 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

View file

@ -0,0 +1,23 @@
/* 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

View file

@ -0,0 +1,13 @@
/* 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

View file

@ -0,0 +1,14 @@
/* 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

View file

@ -17,4 +17,13 @@
#endif
#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

View file

@ -3,23 +3,56 @@
#define __NVKM_DISP_H__
#define nvkm_disp(p) container_of((p), struct nvkm_disp, engine)
#include <core/engine.h>
#include <core/object.h>
#include <core/event.h>
struct nvkm_disp {
const struct nvkm_disp_func *func;
struct nvkm_engine engine;
struct list_head head;
struct list_head ior;
struct list_head outp;
struct list_head conn;
struct list_head heads;
struct list_head iors;
struct list_head outps;
struct list_head conns;
struct nvkm_event hpd;
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 {
spinlock_t lock;
struct nvkm_oproxy *object;
struct nvkm_object object;
} client;
};

View file

@ -54,6 +54,7 @@ struct dcb_output {
} tmdsconf;
};
bool i2c_upper_default;
int id;
};
u16 dcb_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);

View file

@ -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);
else
ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
entry->id = idx;
if (!ret)
return 1; /* stop parsing */

View file

@ -404,6 +404,7 @@ nouveau_connector_destroy(struct drm_connector *connector)
drm_dp_cec_unregister_connector(&nv_connector->aux);
kfree(nv_connector->aux.name);
}
nvif_conn_dtor(&nv_connector->conn);
kfree(connector);
}
@ -1386,6 +1387,15 @@ nouveau_connector_create(struct drm_device *dev,
drm_connector_init(dev, connector, funcs, type);
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);
nouveau_conn_attach_properties(connector);

View file

@ -26,7 +26,7 @@
#ifndef __NOUVEAU_CONNECTOR_H__
#define __NOUVEAU_CONNECTOR_H__
#include <nvif/conn.h>
#include <nvif/notify.h>
#include <nvhw/class/cl507d.h>
@ -123,6 +123,7 @@ struct nouveau_connector {
u8 index;
u8 *dcb;
struct nvif_conn conn;
struct nvif_notify hpd;
struct drm_dp_aux aux;

View file

@ -107,7 +107,7 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector,
struct nv50_mstm *mstm = nv_encoder->dp.mstm;
enum drm_connector_status status;
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
* reread it as it won't change
@ -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);
if (status == connector_status_disconnected)
goto out;

View file

@ -26,7 +26,7 @@
#ifndef __NOUVEAU_ENCODER_H__
#define __NOUVEAU_ENCODER_H__
#include <nvif/outp.h>
#include <subdev/bios/dcb.h>
#include <drm/display/drm_dp_helper.h>
@ -46,6 +46,7 @@ struct nouveau_encoder {
struct drm_encoder_slave base;
struct dcb_output *dcb;
struct nvif_outp outp;
int or;
int link;

View file

@ -1,6 +1,7 @@
# SPDX-License-Identifier: MIT
nvif-y := nvif/object.o
nvif-y += nvif/client.o
nvif-y += nvif/conn.o
nvif-y += nvif/device.o
nvif-y += nvif/disp.o
nvif-y += nvif/driver.o
@ -8,6 +9,7 @@ nvif-y += nvif/fifo.o
nvif-y += nvif/mem.o
nvif-y += nvif/mmu.o
nvif-y += nvif/notify.o
nvif-y += nvif/outp.o
nvif-y += nvif/timer.o
nvif-y += nvif/vmm.o

View file

@ -19,34 +19,44 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "rootnv50.h"
#include "channv50.h"
#include <nvif/conn.h>
#include <nvif/disp.h>
#include <nvif/printf.h>
#include <nvif/class.h>
#include <nvif/if0011.h>
static const struct nv50_disp_root_func
ga102_disp_root = {
.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)
int
nvif_conn_hpd_status(struct nvif_conn *conn)
{
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;
}
const struct nvkm_disp_oclass
ga102_disp_root_oclass = {
.base.oclass = GA102_DISP,
.base.minver = -1,
.base.maxver = -1,
.ctor = ga102_disp_root_new,
};
void
nvif_conn_dtor(struct nvif_conn *conn)
{
nvif_object_dtor(&conn->object);
}
int
nvif_conn_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_conn *conn)
{
struct nvif_conn_v0 args;
int ret;
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;
}

View file

@ -21,8 +21,10 @@
*/
#include <nvif/disp.h>
#include <nvif/device.h>
#include <nvif/printf.h>
#include <nvif/class.h>
#include <nvif/if0010.h>
void
nvif_disp_dtor(struct nvif_disp *disp)
@ -31,33 +33,48 @@ nvif_disp_dtor(struct nvif_disp *disp)
}
int
nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass,
struct nvif_disp *disp)
nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass, struct nvif_disp *disp)
{
static const struct nvif_mclass disps[] = {
{ GA102_DISP, -1 },
{ TU102_DISP, -1 },
{ GV100_DISP, -1 },
{ GP102_DISP, -1 },
{ GP100_DISP, -1 },
{ GM200_DISP, -1 },
{ GM107_DISP, -1 },
{ GK110_DISP, -1 },
{ GK104_DISP, -1 },
{ GF110_DISP, -1 },
{ GT214_DISP, -1 },
{ GT206_DISP, -1 },
{ GT200_DISP, -1 },
{ G82_DISP, -1 },
{ NV50_DISP, -1 },
{ NV04_DISP, -1 },
{ GA102_DISP, 0 },
{ TU102_DISP, 0 },
{ GV100_DISP, 0 },
{ GP102_DISP, 0 },
{ GP100_DISP, 0 },
{ GM200_DISP, 0 },
{ GM107_DISP, 0 },
{ GK110_DISP, 0 },
{ GK104_DISP, 0 },
{ GF110_DISP, 0 },
{ GT214_DISP, 0 },
{ GT206_DISP, 0 },
{ GT200_DISP, 0 },
{ G82_DISP, 0 },
{ NV50_DISP, 0 },
{ NV04_DISP, 0 },
{}
};
int cid = nvif_sclass(&device->object, disps, oclass);
disp->object.client = NULL;
if (cid < 0)
return cid;
struct nvif_disp_v0 args;
int cid, ret;
return nvif_object_ctor(&device->object, name ? name : "nvifDisp", 0,
disps[cid].oclass, NULL, 0, &disp->object);
cid = nvif_sclass(&device->object, disps, oclass);
disp->object.client = NULL;
if (cid < 0) {
NVIF_ERRON(cid, &device->object, "[NEW disp%04x] not supported", oclass);
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;
NVIF_DEBUG(&disp->object, "[NEW] conn_mask:%08x outp_mask:%08x",
args.conn_mask, args.outp_mask);
disp->conn_mask = args.conn_mask;
disp->outp_mask = args.outp_mask;
return 0;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2012 Red Hat Inc.
* Copyright 2021 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"),
@ -18,38 +18,45 @@
* 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 "rootnv50.h"
#include "channv50.h"
#include <nvif/outp.h>
#include <nvif/disp.h>
#include <nvif/printf.h>
#include <nvif/class.h>
#include <nvif/if0012.h>
static const struct nv50_disp_root_func
g94_disp_root = {
.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)
int
nvif_outp_load_detect(struct nvif_outp *outp, u32 loadval)
{
return nv50_disp_root_new_(&g94_disp_root, disp, oclass,
data, size, pobject);
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;
}
const struct nvkm_disp_oclass
g94_disp_root_oclass = {
.base.oclass = GT206_DISP,
.base.minver = -1,
.base.maxver = -1,
.ctor = g94_disp_root_new,
};
void
nvif_outp_dtor(struct nvif_outp *outp)
{
nvif_object_dtor(&outp->object);
}
int
nvif_outp_ctor(struct nvif_disp *disp, const char *name, int id, struct nvif_outp *outp)
{
struct nvif_outp_v0 args;
int ret;
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;
}

View file

@ -1,5 +1,14 @@
# SPDX-License-Identifier: MIT
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/nv50.o
nvkm-y += nvkm/engine/disp/g84.o
@ -18,110 +27,10 @@ nvkm-y += nvkm/engine/disp/gp102.o
nvkm-y += nvkm/engine/disp/gv100.o
nvkm-y += nvkm/engine/disp/tu102.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/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/oimmgf119.o
nvkm-y += nvkm/engine/disp/oimmgp102.o
nvkm-y += nvkm/engine/disp/udisp.o
nvkm-y += nvkm/engine/disp/uconn.o
nvkm-y += nvkm/engine/disp/uoutp.o

View file

@ -30,7 +30,7 @@
#include <core/client.h>
#include <core/notify.h>
#include <core/oproxy.h>
#include <core/ramht.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
@ -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))) {
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 = -ENODEV, outp->conn->hpd.event) {
notify->types = req->v0.mask;
@ -145,45 +145,12 @@ nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event)
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
nvkm_disp_class_new(struct nvkm_device *device,
const struct nvkm_oclass *oclass, void *data, u32 size,
struct nvkm_object **pobject)
{
const struct nvkm_disp_oclass *sclass = oclass->engn;
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);
return nvkm_udisp_new(oclass, data, size, pobject);
}
static const struct nvkm_device_oclass
@ -197,9 +164,7 @@ nvkm_disp_class_get(struct nvkm_oclass *oclass, int index,
{
struct nvkm_disp *disp = nvkm_disp(oclass->engine);
if (index == 0) {
const struct nvkm_disp_oclass *root = disp->func->root(disp);
oclass->base = root->base;
oclass->engn = root;
oclass->base = disp->func->root;
*class = &nvkm_disp_sclass;
return 0;
}
@ -223,11 +188,11 @@ nvkm_disp_fini(struct nvkm_engine *engine, bool suspend)
if (disp->func->fini)
disp->func->fini(disp);
list_for_each_entry(outp, &disp->outp, head) {
list_for_each_entry(outp, &disp->outps, head) {
nvkm_outp_fini(outp);
}
list_for_each_entry(conn, &disp->conn, head) {
list_for_each_entry(conn, &disp->conns, head) {
nvkm_conn_fini(conn);
}
@ -242,11 +207,11 @@ nvkm_disp_init(struct nvkm_engine *engine)
struct nvkm_outp *outp;
struct nvkm_ior *ior;
list_for_each_entry(conn, &disp->conn, head) {
list_for_each_entry(conn, &disp->conns, head) {
nvkm_conn_init(conn);
}
list_for_each_entry(outp, &disp->outp, head) {
list_for_each_entry(outp, &disp->outps, head) {
nvkm_outp_init(outp);
}
@ -259,7 +224,7 @@ nvkm_disp_init(struct nvkm_engine *engine)
/* Set 'normal' (ie. when it's attached to a head) state for
* 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);
}
@ -326,12 +291,12 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
continue;
}
list_add_tail(&outp->head, &disp->outp);
list_add_tail(&outp->head, &disp->outps);
hpd = max(hpd, (u8)(dcbE.connector + 1));
}
/* 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. */
data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr,
&connE);
@ -345,7 +310,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
*/
int ccb_index = outp->info.i2c_index;
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) {
outp->conn = pair->conn;
break;
@ -365,7 +330,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
}
/* 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) {
outp->conn = conn;
break;
@ -387,7 +352,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
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);
@ -403,7 +368,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
/* Enforce identity-mapped SOR assignment for panels, which have
* 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 ||
outp->conn->info.type == DCB_CONNECTOR_eDP) {
ior = nvkm_ior_find(disp, SOR, ffs(outp->info.or) - 1);
@ -414,7 +379,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine)
}
i = 0;
list_for_each_entry(head, &disp->head, head)
list_for_each_entry(head, &disp->heads, head)
i = max(i, head->id + 1);
return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank);
@ -426,35 +391,42 @@ nvkm_disp_dtor(struct nvkm_engine *engine)
struct nvkm_disp *disp = nvkm_disp(engine);
struct nvkm_conn *conn;
struct nvkm_outp *outp;
struct nvkm_ior *ior;
struct nvkm_head *head;
void *data = disp;
if (disp->func->dtor)
data = disp->func->dtor(disp);
nvkm_ramht_del(&disp->ramht);
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->hpd);
while (!list_empty(&disp->conn)) {
conn = list_first_entry(&disp->conn, typeof(*conn), head);
while (!list_empty(&disp->conns)) {
conn = list_first_entry(&disp->conns, typeof(*conn), head);
list_del(&conn->head);
nvkm_conn_del(&conn);
}
while (!list_empty(&disp->outp)) {
outp = list_first_entry(&disp->outp, typeof(*outp), head);
while (!list_empty(&disp->outps)) {
outp = list_first_entry(&disp->outps, typeof(*outp), head);
list_del(&outp->head);
nvkm_outp_del(&outp);
}
while (!list_empty(&disp->ior)) {
struct nvkm_ior *ior =
list_first_entry(&disp->ior, typeof(*ior), head);
while (!list_empty(&disp->iors)) {
ior = list_first_entry(&disp->iors, typeof(*ior), head);
nvkm_ior_del(&ior);
}
while (!list_empty(&disp->head)) {
struct nvkm_head *head =
list_first_entry(&disp->head, typeof(*head), head);
while (!list_empty(&disp->heads)) {
head = list_first_entry(&disp->heads, typeof(*head), head);
nvkm_head_del(&head);
}
@ -471,24 +443,35 @@ nvkm_disp = {
.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
nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device,
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 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);
}

View file

@ -1,74 +0,0 @@
/*
* 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);
}

View file

@ -1,108 +0,0 @@
/*
* 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);
}

View file

@ -1,32 +0,0 @@
/*
* 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);
}

View file

@ -1,119 +0,0 @@
/*
* 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);
}

View file

@ -1,60 +0,0 @@
/*
* 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.
*/
#define gv100_disp_caps(p) container_of((p), struct gv100_disp_caps, object)
#include "rootnv50.h"
struct gv100_disp_caps {
struct nvkm_object object;
struct nv50_disp *disp;
};
static int
gv100_disp_caps_map(struct nvkm_object *object, void *argv, u32 argc,
enum nvkm_object_map *type, u64 *addr, u64 *size)
{
struct gv100_disp_caps *caps = gv100_disp_caps(object);
struct nvkm_device *device = caps->disp->base.engine.subdev.device;
*type = NVKM_OBJECT_MAP_IO;
*addr = 0x640000 + device->func->resource_addr(device, 0);
*size = 0x1000;
return 0;
}
static const struct nvkm_object_func
gv100_disp_caps = {
.map = gv100_disp_caps_map,
};
int
gv100_disp_caps_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nv50_disp *disp, struct nvkm_object **pobject)
{
struct gv100_disp_caps *caps;
if (!(caps = kzalloc(sizeof(*caps), GFP_KERNEL)))
return -ENOMEM;
*pobject = &caps->object;
nvkm_object_ctor(&gv100_disp_caps, oclass, &caps->object);
caps->disp = disp;
return 0;
}

View file

@ -0,0 +1,275 @@
/*
* Copyright 2021 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 "chan.h"
#include <core/oproxy.h>
#include <core/ramht.h>
#include <nvif/if0014.h>
static int
nvkm_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device;
u64 size, base = chan->func->user(chan, &size);
*data = nvkm_rd32(device, base + addr);
return 0;
}
static int
nvkm_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device;
u64 size, base = chan->func->user(chan, &size);
nvkm_wr32(device, base + addr, data);
return 0;
}
static int
nvkm_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pevent)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_disp *disp = chan->disp;
switch (type) {
case 0:
*pevent = &disp->uevent;
return 0;
default:
break;
}
return -EINVAL;
}
static int
nvkm_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc,
enum nvkm_object_map *type, u64 *addr, u64 *size)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device;
const u64 base = device->func->resource_addr(device, 0);
*type = NVKM_OBJECT_MAP_IO;
*addr = base + chan->func->user(chan, size);
return 0;
}
struct nvkm_disp_chan_object {
struct nvkm_oproxy oproxy;
struct nvkm_disp *disp;
int hash;
};
static void
nvkm_disp_chan_child_del_(struct nvkm_oproxy *base)
{
struct nvkm_disp_chan_object *object = container_of(base, typeof(*object), oproxy);
nvkm_ramht_remove(object->disp->ramht, object->hash);
}
static const struct nvkm_oproxy_func
nvkm_disp_chan_child_func_ = {
.dtor[0] = nvkm_disp_chan_child_del_,
};
static int
nvkm_disp_chan_child_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(oclass->parent);
struct nvkm_disp *disp = chan->disp;
struct nvkm_device *device = disp->engine.subdev.device;
const struct nvkm_device_oclass *sclass = oclass->priv;
struct nvkm_disp_chan_object *object;
int ret;
if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
return -ENOMEM;
nvkm_oproxy_ctor(&nvkm_disp_chan_child_func_, oclass, &object->oproxy);
object->disp = disp;
*pobject = &object->oproxy.base;
ret = sclass->ctor(device, oclass, argv, argc, &object->oproxy.object);
if (ret)
return ret;
object->hash = chan->func->bind(chan, object->oproxy.object, oclass->handle);
if (object->hash < 0)
return object->hash;
return 0;
}
static int
nvkm_disp_chan_child_get(struct nvkm_object *object, int index, struct nvkm_oclass *sclass)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_device *device = chan->disp->engine.subdev.device;
const struct nvkm_device_oclass *oclass = NULL;
if (chan->func->bind)
sclass->engine = nvkm_device_engine(device, NVKM_ENGINE_DMAOBJ, 0);
else
sclass->engine = NULL;
if (sclass->engine && sclass->engine->func->base.sclass) {
sclass->engine->func->base.sclass(sclass, index, &oclass);
if (oclass) {
sclass->ctor = nvkm_disp_chan_child_new;
sclass->priv = oclass;
return 0;
}
}
return -EINVAL;
}
static int
nvkm_disp_chan_fini(struct nvkm_object *object, bool suspend)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
chan->func->fini(chan);
chan->func->intr(chan, false);
return 0;
}
static int
nvkm_disp_chan_init(struct nvkm_object *object)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
chan->func->intr(chan, true);
return chan->func->init(chan);
}
static void *
nvkm_disp_chan_dtor(struct nvkm_object *object)
{
struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
struct nvkm_disp *disp = chan->disp;
spin_lock(&disp->client.lock);
if (disp->chan[chan->chid.user] == chan)
disp->chan[chan->chid.user] = NULL;
spin_unlock(&disp->client.lock);
nvkm_memory_unref(&chan->memory);
return chan;
}
static const struct nvkm_object_func
nvkm_disp_chan = {
.dtor = nvkm_disp_chan_dtor,
.init = nvkm_disp_chan_init,
.fini = nvkm_disp_chan_fini,
.rd32 = nvkm_disp_chan_rd32,
.wr32 = nvkm_disp_chan_wr32,
.ntfy = nvkm_disp_chan_ntfy,
.map = nvkm_disp_chan_map,
.sclass = nvkm_disp_chan_child_get,
};
static int
nvkm_disp_chan_new_(struct nvkm_disp *disp, int nr, const struct nvkm_oclass *oclass,
void *argv, u32 argc, struct nvkm_object **pobject)
{
const struct nvkm_disp_chan_user *user = NULL;
struct nvkm_disp_chan *chan;
union nvif_disp_chan_args *args = argv;
int ret, i;
for (i = 0; disp->func->user[i].ctor; i++) {
if (disp->func->user[i].base.oclass == oclass->base.oclass) {
user = disp->func->user[i].chan;
break;
}
}
if (WARN_ON(!user))
return -EINVAL;
if (argc != sizeof(args->v0) || args->v0.version != 0)
return -ENOSYS;
if (args->v0.id >= nr || !args->v0.pushbuf != !user->func->push)
return -EINVAL;
if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
return -ENOMEM;
*pobject = &chan->object;
nvkm_object_ctor(&nvkm_disp_chan, oclass, &chan->object);
chan->func = user->func;
chan->mthd = user->mthd;
chan->disp = disp;
chan->chid.ctrl = user->ctrl + args->v0.id;
chan->chid.user = user->user + args->v0.id;
chan->head = args->v0.id;
if (chan->func->push) {
ret = chan->func->push(chan, args->v0.pushbuf);
if (ret)
return ret;
}
spin_lock(&disp->client.lock);
if (disp->chan[chan->chid.user]) {
spin_unlock(&disp->client.lock);
return -EBUSY;
}
disp->chan[chan->chid.user] = chan;
spin_unlock(&disp->client.lock);
return 0;
}
int
nvkm_disp_wndw_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
return nvkm_disp_chan_new_(disp, disp->wndw.nr, oclass, argv, argc, pobject);
}
int
nvkm_disp_chan_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
return nvkm_disp_chan_new_(disp, disp->head.nr, oclass, argv, argc, pobject);
}
int
nvkm_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
struct nvkm_object **pobject)
{
struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
return nvkm_disp_chan_new_(disp, 1, oclass, argv, argc, pobject);
}

View file

@ -0,0 +1,135 @@
/* 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

View file

@ -1,62 +0,0 @@
/*
* 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);
}
}

View file

@ -1,34 +0,0 @@
/*
* 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);
}

View file

@ -1,364 +0,0 @@
/*
* 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 "rootnv50.h"
#include <core/client.h>
#include <core/notify.h>
#include <core/oproxy.h>
#include <core/ramht.h>
#include <engine/dma.h>
#include <nvif/cl507d.h>
#include <nvif/event.h>
#include <nvif/unpack.h>
static void
nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c,
const struct nv50_disp_mthd_list *list, int inst)
{
struct nvkm_subdev *subdev = &disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
int i;
for (i = 0; list->data[i].mthd; i++) {
if (list->data[i].addr) {
u32 next = nvkm_rd32(device, list->data[i].addr + base + 0);
u32 prev = nvkm_rd32(device, list->data[i].addr + base + c);
u32 mthd = list->data[i].mthd + (list->mthd * inst);
const char *name = list->data[i].name;
char mods[16];
if (prev != next)
snprintf(mods, sizeof(mods), "-> %08x", next);
else
snprintf(mods, sizeof(mods), "%13c", ' ');
nvkm_printk_(subdev, debug, info,
"\t%04x: %08x %s%s%s\n",
mthd, prev, mods, name ? " // " : "",
name ? name : "");
}
}
}
void
nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug)
{
struct nv50_disp *disp = chan->disp;
struct nvkm_subdev *subdev = &disp->base.engine.subdev;
const struct nv50_disp_chan_mthd *mthd = chan->mthd;
const struct nv50_disp_mthd_list *list;
int i, j;
if (debug > subdev->debug)
return;
if (!mthd)
return;
for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) {
u32 base = chan->head * mthd->addr;
for (j = 0; j < mthd->data[i].nr; j++, base += list->addr) {
const char *cname = mthd->name;
const char *sname = "";
char cname_[16], sname_[16];
if (mthd->addr) {
snprintf(cname_, sizeof(cname_), "%s %d",
mthd->name, chan->chid.user);
cname = cname_;
}
if (mthd->data[i].nr > 1) {
snprintf(sname_, sizeof(sname_), " - %s %d",
mthd->data[i].name, j);
sname = sname_;
}
nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname);
nv50_disp_mthd_list(disp, debug, base, mthd->prev,
list, j);
}
}
}
static void
nv50_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, 0x610028, 0x00000001 << index, 0x00000000 << index);
nvkm_wr32(device, 0x610020, 0x00000001 << index);
}
static void
nv50_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, 0x610020, 0x00000001 << index);
nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000001 << index);
}
void
nv50_disp_chan_uevent_send(struct nv50_disp *disp, int chid)
{
struct nvif_notify_uevent_rep {
} rep;
nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep));
}
int
nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
union {
struct nvif_notify_uevent_req none;
} *args = data;
int ret = -ENOSYS;
if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
notify->size = sizeof(struct nvif_notify_uevent_rep);
notify->types = 1;
notify->index = chan->chid.user;
return 0;
}
return ret;
}
const struct nvkm_event_func
nv50_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
.init = nv50_disp_chan_uevent_init,
.fini = nv50_disp_chan_uevent_fini,
};
u64
nv50_disp_chan_user(struct nv50_disp_chan *chan, u64 *psize)
{
*psize = 0x1000;
return 0x640000 + (chan->chid.user * 0x1000);
}
void
nv50_disp_chan_intr(struct nv50_disp_chan *chan, bool en)
{
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u32 mask = 0x00010001 << chan->chid.user;
const u32 data = en ? 0x00010000 << chan->chid.user : 0x00000000;
nvkm_mask(device, 0x610028, mask, data);
}
static int
nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
u64 size, base = chan->func->user(chan, &size);
*data = nvkm_rd32(device, base + addr);
return 0;
}
static int
nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
u64 size, base = chan->func->user(chan, &size);
nvkm_wr32(device, base + addr, data);
return 0;
}
static int
nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type,
struct nvkm_event **pevent)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
struct nv50_disp *disp = chan->disp;
switch (type) {
case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
*pevent = &disp->uevent;
return 0;
default:
break;
}
return -EINVAL;
}
static int
nv50_disp_chan_map(struct nvkm_object *object, void *argv, u32 argc,
enum nvkm_object_map *type, u64 *addr, u64 *size)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const u64 base = device->func->resource_addr(device, 0);
*type = NVKM_OBJECT_MAP_IO;
*addr = base + chan->func->user(chan, size);
return 0;
}
struct nv50_disp_chan_object {
struct nvkm_oproxy oproxy;
struct nv50_disp *disp;
int hash;
};
static void
nv50_disp_chan_child_del_(struct nvkm_oproxy *base)
{
struct nv50_disp_chan_object *object =
container_of(base, typeof(*object), oproxy);
nvkm_ramht_remove(object->disp->ramht, object->hash);
}
static const struct nvkm_oproxy_func
nv50_disp_chan_child_func_ = {
.dtor[0] = nv50_disp_chan_child_del_,
};
static int
nv50_disp_chan_child_new(const struct nvkm_oclass *oclass,
void *argv, u32 argc, struct nvkm_object **pobject)
{
struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent);
struct nv50_disp *disp = chan->disp;
struct nvkm_device *device = disp->base.engine.subdev.device;
const struct nvkm_device_oclass *sclass = oclass->priv;
struct nv50_disp_chan_object *object;
int ret;
if (!(object = kzalloc(sizeof(*object), GFP_KERNEL)))
return -ENOMEM;
nvkm_oproxy_ctor(&nv50_disp_chan_child_func_, oclass, &object->oproxy);
object->disp = disp;
*pobject = &object->oproxy.base;
ret = sclass->ctor(device, oclass, argv, argc, &object->oproxy.object);
if (ret)
return ret;
object->hash = chan->func->bind(chan, object->oproxy.object,
oclass->handle);
if (object->hash < 0)
return object->hash;
return 0;
}
static int
nv50_disp_chan_child_get(struct nvkm_object *object, int index,
struct nvkm_oclass *sclass)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
struct nvkm_device *device = chan->disp->base.engine.subdev.device;
const struct nvkm_device_oclass *oclass = NULL;
if (chan->func->bind)
sclass->engine = nvkm_device_engine(device, NVKM_ENGINE_DMAOBJ, 0);
else
sclass->engine = NULL;
if (sclass->engine && sclass->engine->func->base.sclass) {
sclass->engine->func->base.sclass(sclass, index, &oclass);
if (oclass) {
sclass->ctor = nv50_disp_chan_child_new,
sclass->priv = oclass;
return 0;
}
}
return -EINVAL;
}
static int
nv50_disp_chan_fini(struct nvkm_object *object, bool suspend)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
chan->func->fini(chan);
chan->func->intr(chan, false);
return 0;
}
static int
nv50_disp_chan_init(struct nvkm_object *object)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
chan->func->intr(chan, true);
return chan->func->init(chan);
}
static void *
nv50_disp_chan_dtor(struct nvkm_object *object)
{
struct nv50_disp_chan *chan = nv50_disp_chan(object);
struct nv50_disp *disp = chan->disp;
if (chan->chid.user >= 0)
disp->chan[chan->chid.user] = NULL;
nvkm_memory_unref(&chan->memory);
return chan;
}
static const struct nvkm_object_func
nv50_disp_chan = {
.dtor = nv50_disp_chan_dtor,
.init = nv50_disp_chan_init,
.fini = nv50_disp_chan_fini,
.rd32 = nv50_disp_chan_rd32,
.wr32 = nv50_disp_chan_wr32,
.ntfy = nv50_disp_chan_ntfy,
.map = nv50_disp_chan_map,
.sclass = nv50_disp_chan_child_get,
};
int
nv50_disp_chan_new_(const struct nv50_disp_chan_func *func,
const struct nv50_disp_chan_mthd *mthd,
struct nv50_disp *disp, int ctrl, int user, int head,
const struct nvkm_oclass *oclass,
struct nvkm_object **pobject)
{
struct nv50_disp_chan *chan;
if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
return -ENOMEM;
*pobject = &chan->object;
nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object);
chan->func = func;
chan->mthd = mthd;
chan->disp = disp;
chan->chid.ctrl = ctrl;
chan->chid.user = user;
chan->head = head;
if (disp->chan[chan->chid.user]) {
chan->chid.user = -1;
return -EBUSY;
}
disp->chan[chan->chid.user] = chan;
return 0;
}

View file

@ -1,193 +0,0 @@
/* 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

View file

@ -86,6 +86,7 @@ nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
conn->disp = disp;
conn->index = index;
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",
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,
ret = nvkm_gpio_find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
if (ret) {
CONN_ERR(conn, "func %02x lookup failed, %d",
info->hpd, ret);
CONN_ERR(conn, "func %02x lookup failed, %d", info->hpd, ret);
return;
}
conn->info.hpd = func.line;
ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd,
true, &(struct nvkm_gpio_ntfy_req) {
.mask = NVKM_GPIO_TOGGLED,

View file

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_DISP_CONN_H__
#define __NVKM_DISP_CONN_H__
#include <engine/disp.h>
#include "priv.h"
#include <core/notify.h>
#include <subdev/bios.h>
@ -15,6 +15,8 @@ struct nvkm_conn {
struct nvkm_notify hpd;
struct list_head head;
struct nvkm_object object;
};
int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *,

View file

@ -1,111 +0,0 @@
/*
* 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);
}

View file

@ -1,57 +0,0 @@
/*
* 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);
}

View file

@ -1,231 +0,0 @@
/*
* 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);
}

View file

@ -1,126 +0,0 @@
/*
* 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);
}

View file

@ -1,70 +0,0 @@
/*
* 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);
}

View file

@ -1,207 +0,0 @@
/*
* 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);
}

View file

@ -1,234 +0,0 @@
/*
* 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);
}

View file

@ -1,32 +0,0 @@
/*
* 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);
}

View file

@ -1,32 +0,0 @@
/*
* 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);
}

View file

@ -1,81 +0,0 @@
/*
* 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);
}

View file

@ -1,64 +0,0 @@
/*
* 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);
}

View file

@ -1,70 +0,0 @@
/*
* 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;
}

View file

@ -1,121 +0,0 @@
/*
* 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;
}

View file

@ -1,96 +0,0 @@
/*
* 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/ramht.h>
#include <subdev/timer.h>
int
gf119_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 << 27 | 0x00000001);
}
void
gf119_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, 0x610490 + (ctrl * 0x0010), 0x00001010, 0x00001000);
nvkm_mask(device, 0x610490 + (ctrl * 0x0010), 0x00000003, 0x00000000);
if (nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x610490 + (ctrl * 0x10)) & 0x001e0000))
break;
) < 0) {
nvkm_error(subdev, "ch %d fini: %08x\n", user,
nvkm_rd32(device, 0x610490 + (ctrl * 0x10)));
}
chan->suspend_put = nvkm_rd32(device, 0x640000 + (ctrl * 0x1000));
}
static int
gf119_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, 0x610494 + (ctrl * 0x0010), chan->push);
nvkm_wr32(device, 0x610498 + (ctrl * 0x0010), 0x00010000);
nvkm_wr32(device, 0x61049c + (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
gf119_disp_dmac_func = {
.init = gf119_disp_dmac_init,
.fini = gf119_disp_dmac_fini,
.intr = gf119_disp_chan_intr,
.user = nv50_disp_chan_user,
.bind = gf119_disp_dmac_bind,
};

View file

@ -1,64 +0,0 @@
/*
* 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,
};

View file

@ -1,79 +0,0 @@
/*
* 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);
}

View file

@ -1,137 +0,0 @@
/*
* 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,
};

View file

@ -40,7 +40,7 @@
#define AMPERE_IED_HACK(disp) ((disp)->engine.subdev.device->card_type >= GA100)
struct lt_state {
struct nvkm_dp *dp;
struct nvkm_outp *outp;
int repeaters;
int repeater;
@ -55,7 +55,7 @@ struct lt_state {
static int
nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay)
{
struct nvkm_dp *dp = lt->dp;
struct nvkm_outp *outp = lt->outp;
u32 addr;
int ret;
@ -66,7 +66,7 @@ nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay)
else
addr = DPCD_LS02;
ret = nvkm_rdaux(dp->aux, addr, &lt->stat[0], 3);
ret = nvkm_rdaux(outp->dp.aux, addr, &lt->stat[0], 3);
if (ret)
return ret;
@ -75,18 +75,18 @@ nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay)
else
addr = DPCD_LS06;
ret = nvkm_rdaux(dp->aux, addr, &lt->stat[4], 2);
ret = nvkm_rdaux(outp->dp.aux, addr, &lt->stat[4], 2);
if (ret)
return ret;
if (pc) {
ret = nvkm_rdaux(dp->aux, DPCD_LS0C, &lt->pc2stat, 1);
ret = nvkm_rdaux(outp->dp.aux, DPCD_LS0C, &lt->pc2stat, 1);
if (ret)
lt->pc2stat = 0x00;
OUTP_TRACE(&dp->outp, "status %6ph pc2 %02x",
lt->stat, lt->pc2stat);
OUTP_TRACE(outp, "status %6ph pc2 %02x", lt->stat, lt->pc2stat);
} else {
OUTP_TRACE(&dp->outp, "status %6ph", lt->stat);
OUTP_TRACE(outp, "status %6ph", lt->stat);
}
return 0;
@ -95,8 +95,8 @@ nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay)
static int
nvkm_dp_train_drive(struct lt_state *lt, bool pc)
{
struct nvkm_dp *dp = lt->dp;
struct nvkm_ior *ior = dp->outp.ior;
struct nvkm_outp *outp = lt->outp;
struct nvkm_ior *ior = outp->ior;
struct nvkm_bios *bios = ior->disp->engine.subdev.device->bios;
struct nvbios_dpout info;
struct nvbios_dpcfg ocfg;
@ -127,26 +127,22 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc)
lt->conf[i] = (lpre << 3) | lvsw;
lt->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
OUTP_TRACE(&dp->outp, "config lane %d %02x %02x",
i, lt->conf[i], lpc2);
OUTP_TRACE(outp, "config lane %d %02x %02x", i, lt->conf[i], lpc2);
if (lt->repeater != lt->repeaters)
continue;
data = nvbios_dpout_match(bios, dp->outp.info.hasht,
dp->outp.info.hashm,
data = nvbios_dpout_match(bios, outp->info.hasht, outp->info.hashm,
&ver, &hdr, &cnt, &len, &info);
if (!data)
continue;
data = nvbios_dpcfg_match(bios, data, lpc2 & 3, lvsw & 3,
lpre & 3, &ver, &hdr, &cnt, &len,
&ocfg);
data = nvbios_dpcfg_match(bios, data, lpc2 & 3, lvsw & 3, lpre & 3,
&ver, &hdr, &cnt, &len, &ocfg);
if (!data)
continue;
ior->func->dp.drive(ior, i, ocfg.pc, ocfg.dc,
ocfg.pe, ocfg.tx_pu);
ior->func->dp->drive(ior, i, ocfg.pc, ocfg.dc, ocfg.pe, ocfg.tx_pu);
}
if (lt->repeater)
@ -154,12 +150,12 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc)
else
addr = DPCD_LC03(0);
ret = nvkm_wraux(dp->aux, addr, lt->conf, 4);
ret = nvkm_wraux(outp->dp.aux, addr, lt->conf, 4);
if (ret)
return ret;
if (pc) {
ret = nvkm_wraux(dp->aux, DPCD_LC0F, lt->pc2conf, 2);
ret = nvkm_wraux(outp->dp.aux, DPCD_LC0F, lt->pc2conf, 2);
if (ret)
return ret;
}
@ -170,19 +166,19 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc)
static void
nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern)
{
struct nvkm_dp *dp = lt->dp;
struct nvkm_outp *outp = lt->outp;
u32 addr;
u8 sink_tp;
OUTP_TRACE(&dp->outp, "training pattern %d", pattern);
dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern);
OUTP_TRACE(outp, "training pattern %d", pattern);
outp->ior->func->dp->pattern(outp->ior, pattern);
if (lt->repeater)
addr = DPCD_LTTPR_PATTERN_SET(lt->repeater);
else
addr = DPCD_LC02;
nvkm_rdaux(dp->aux, addr, &sink_tp, 1);
nvkm_rdaux(outp->dp.aux, addr, &sink_tp, 1);
sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
sink_tp |= (pattern != 4) ? pattern : 7;
@ -190,13 +186,13 @@ nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern)
sink_tp |= DPCD_LC02_SCRAMBLING_DISABLE;
else
sink_tp &= ~DPCD_LC02_SCRAMBLING_DISABLE;
nvkm_wraux(dp->aux, addr, &sink_tp, 1);
nvkm_wraux(outp->dp.aux, addr, &sink_tp, 1);
}
static int
nvkm_dp_train_eq(struct lt_state *lt)
{
struct nvkm_i2c_aux *aux = lt->dp->aux;
struct nvkm_i2c_aux *aux = lt->outp->dp.aux;
bool eq_done = false, cr_done = true;
int tries = 0, usec = 0, i;
u8 data;
@ -207,17 +203,17 @@ nvkm_dp_train_eq(struct lt_state *lt)
nvkm_dp_train_pattern(lt, 4);
} else {
if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x14 &&
lt->dp->dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED)
if (lt->outp->dp.dpcd[DPCD_RC00_DPCD_REV] >= 0x14 &&
lt->outp->dp.dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED)
nvkm_dp_train_pattern(lt, 4);
else
if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x12 &&
lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED)
if (lt->outp->dp.dpcd[DPCD_RC00_DPCD_REV] >= 0x12 &&
lt->outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED)
nvkm_dp_train_pattern(lt, 3);
else
nvkm_dp_train_pattern(lt, 2);
usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000;
usec = (lt->outp->dp.dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000;
}
do {
@ -227,7 +223,7 @@ nvkm_dp_train_eq(struct lt_state *lt)
break;
eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
for (i = 0; i < lt->dp->outp.ior->dp.nr && eq_done; i++) {
for (i = 0; i < lt->outp->ior->dp.nr && eq_done; i++) {
u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
if (!(lane & DPCD_LS02_LANE0_CR_DONE))
cr_done = false;
@ -249,8 +245,8 @@ nvkm_dp_train_cr(struct lt_state *lt)
nvkm_dp_train_pattern(lt, 1);
if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] < 0x14 && !lt->repeater)
usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000;
if (lt->outp->dp.dpcd[DPCD_RC00_DPCD_REV] < 0x14 && !lt->repeater)
usec = (lt->outp->dp.dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000;
do {
if (nvkm_dp_train_drive(lt, false) ||
@ -258,7 +254,7 @@ nvkm_dp_train_cr(struct lt_state *lt)
break;
cr_done = true;
for (i = 0; i < lt->dp->outp.ior->dp.nr; i++) {
for (i = 0; i < lt->outp->ior->dp.nr; i++) {
u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
cr_done = false;
@ -278,45 +274,44 @@ nvkm_dp_train_cr(struct lt_state *lt)
}
static int
nvkm_dp_train_links(struct nvkm_dp *dp, int rate)
nvkm_dp_train_links(struct nvkm_outp *outp, int rate)
{
struct nvkm_ior *ior = dp->outp.ior;
struct nvkm_disp *disp = dp->outp.disp;
struct nvkm_ior *ior = outp->ior;
struct nvkm_disp *disp = outp->disp;
struct nvkm_subdev *subdev = &disp->engine.subdev;
struct nvkm_bios *bios = subdev->device->bios;
struct lt_state lt = {
.dp = dp,
.outp = outp,
};
u32 lnkcmp;
u8 sink[2], data;
int ret;
OUTP_DBG(&dp->outp, "training %d x %d MB/s",
ior->dp.nr, ior->dp.bw * 27);
OUTP_DBG(outp, "training %d x %d MB/s", ior->dp.nr, ior->dp.bw * 27);
/* Intersect misc. capabilities of the OR and sink. */
if (disp->engine.subdev.device->chipset < 0x110)
dp->dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED;
outp->dp.dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED;
if (disp->engine.subdev.device->chipset < 0xd0)
dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED;
outp->dp.dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
lt.pc2 = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED;
if (AMPERE_IED_HACK(disp) && (lnkcmp = lt.dp->info.script[0])) {
if (AMPERE_IED_HACK(disp) && (lnkcmp = lt.outp->dp.info.script[0])) {
/* Execute BeforeLinkTraining script from DP Info table. */
while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
lnkcmp += 3;
lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
nvbios_init(&dp->outp.disp->engine.subdev, lnkcmp,
init.outp = &dp->outp.info;
nvbios_init(&outp->disp->engine.subdev, lnkcmp,
init.outp = &outp->info;
init.or = ior->id;
init.link = ior->asy.link;
);
}
/* Set desired link configuration on the source. */
if ((lnkcmp = lt.dp->info.lnkcmp)) {
if (dp->version < 0x30) {
if ((lnkcmp = lt.outp->dp.info.lnkcmp)) {
if (outp->dp.version < 0x30) {
while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp))
lnkcmp += 4;
lnkcmp = nvbios_rd16(bios, lnkcmp + 2);
@ -327,56 +322,56 @@ nvkm_dp_train_links(struct nvkm_dp *dp, int rate)
}
nvbios_init(subdev, lnkcmp,
init.outp = &dp->outp.info;
init.outp = &outp->info;
init.or = ior->id;
init.link = ior->asy.link;
);
}
ret = ior->func->dp.links(ior, dp->aux);
ret = ior->func->dp->links(ior, outp->dp.aux);
if (ret) {
if (ret < 0) {
OUTP_ERR(&dp->outp, "train failed with %d", ret);
OUTP_ERR(outp, "train failed with %d", ret);
return ret;
}
return 0;
}
ior->func->dp.power(ior, ior->dp.nr);
ior->func->dp->power(ior, ior->dp.nr);
/* Select LTTPR non-transparent mode if we have a valid configuration,
* use transparent mode otherwise.
*/
if (dp->lttpr[0] >= 0x14) {
if (outp->dp.lttpr[0] >= 0x14) {
data = DPCD_LTTPR_MODE_TRANSPARENT;
nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data));
nvkm_wraux(outp->dp.aux, DPCD_LTTPR_MODE, &data, sizeof(data));
if (dp->lttprs) {
if (outp->dp.lttprs) {
data = DPCD_LTTPR_MODE_NON_TRANSPARENT;
nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data));
lt.repeaters = dp->lttprs;
nvkm_wraux(outp->dp.aux, DPCD_LTTPR_MODE, &data, sizeof(data));
lt.repeaters = outp->dp.lttprs;
}
}
/* Set desired link configuration on the sink. */
sink[0] = (dp->rate[rate].dpcd < 0) ? ior->dp.bw : 0;
sink[0] = (outp->dp.rate[rate].dpcd < 0) ? ior->dp.bw : 0;
sink[1] = ior->dp.nr;
if (ior->dp.ef)
sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
ret = nvkm_wraux(dp->aux, DPCD_LC00_LINK_BW_SET, sink, 2);
ret = nvkm_wraux(outp->dp.aux, DPCD_LC00_LINK_BW_SET, sink, 2);
if (ret)
return ret;
if (dp->rate[rate].dpcd >= 0) {
ret = nvkm_rdaux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0]));
if (outp->dp.rate[rate].dpcd >= 0) {
ret = nvkm_rdaux(outp->dp.aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0]));
if (ret)
return ret;
sink[0] &= ~DPCD_LC15_LINK_RATE_SET_MASK;
sink[0] |= dp->rate[rate].dpcd;
sink[0] |= outp->dp.rate[rate].dpcd;
ret = nvkm_wraux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0]));
ret = nvkm_wraux(outp->dp.aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0]));
if (ret)
return ret;
}
@ -384,9 +379,9 @@ nvkm_dp_train_links(struct nvkm_dp *dp, int rate)
/* Attempt to train the link in this configuration. */
for (lt.repeater = lt.repeaters; lt.repeater >= 0; lt.repeater--) {
if (lt.repeater)
OUTP_DBG(&dp->outp, "training LTTPR%d", lt.repeater);
OUTP_DBG(outp, "training LTTPR%d", lt.repeater);
else
OUTP_DBG(&dp->outp, "training sink");
OUTP_DBG(outp, "training sink");
memset(lt.stat, 0x00, sizeof(lt.stat));
ret = nvkm_dp_train_cr(&lt);
@ -399,94 +394,92 @@ nvkm_dp_train_links(struct nvkm_dp *dp, int rate)
}
static void
nvkm_dp_train_fini(struct nvkm_dp *dp)
nvkm_dp_train_fini(struct nvkm_outp *outp)
{
/* Execute AfterLinkTraining script from DP Info table. */
nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[1],
init.outp = &dp->outp.info;
init.or = dp->outp.ior->id;
init.link = dp->outp.ior->asy.link;
nvbios_init(&outp->disp->engine.subdev, outp->dp.info.script[1],
init.outp = &outp->info;
init.or = outp->ior->id;
init.link = outp->ior->asy.link;
);
}
static void
nvkm_dp_train_init(struct nvkm_dp *dp)
nvkm_dp_train_init(struct nvkm_outp *outp)
{
/* Execute EnableSpread/DisableSpread script from DP Info table. */
if (dp->dpcd[DPCD_RC03] & DPCD_RC03_MAX_DOWNSPREAD) {
nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[2],
init.outp = &dp->outp.info;
init.or = dp->outp.ior->id;
init.link = dp->outp.ior->asy.link;
if (outp->dp.dpcd[DPCD_RC03] & DPCD_RC03_MAX_DOWNSPREAD) {
nvbios_init(&outp->disp->engine.subdev, outp->dp.info.script[2],
init.outp = &outp->info;
init.or = outp->ior->id;
init.link = outp->ior->asy.link;
);
} else {
nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[3],
init.outp = &dp->outp.info;
init.or = dp->outp.ior->id;
init.link = dp->outp.ior->asy.link;
nvbios_init(&outp->disp->engine.subdev, outp->dp.info.script[3],
init.outp = &outp->info;
init.or = outp->ior->id;
init.link = outp->ior->asy.link;
);
}
if (!AMPERE_IED_HACK(dp->outp.disp)) {
if (!AMPERE_IED_HACK(outp->disp)) {
/* Execute BeforeLinkTraining script from DP Info table. */
nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[0],
init.outp = &dp->outp.info;
init.or = dp->outp.ior->id;
init.link = dp->outp.ior->asy.link;
nvbios_init(&outp->disp->engine.subdev, outp->dp.info.script[0],
init.outp = &outp->info;
init.or = outp->ior->id;
init.link = outp->ior->asy.link;
);
}
}
static int
nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps)
nvkm_dp_train(struct nvkm_outp *outp, u32 dataKBps)
{
struct nvkm_ior *ior = dp->outp.ior;
struct nvkm_ior *ior = outp->ior;
int ret = -EINVAL, nr, rate;
u8 pwr;
/* Ensure sink is not in a low-power state. */
if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) {
if (!nvkm_rdaux(outp->dp.aux, DPCD_SC00, &pwr, 1)) {
if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) {
pwr &= ~DPCD_SC00_SET_POWER;
pwr |= DPCD_SC00_SET_POWER_D0;
nvkm_wraux(dp->aux, DPCD_SC00, &pwr, 1);
nvkm_wraux(outp->dp.aux, DPCD_SC00, &pwr, 1);
}
}
ior->dp.mst = dp->lt.mst;
ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP;
ior->dp.mst = outp->dp.lt.mst;
ior->dp.ef = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP;
ior->dp.nr = 0;
/* Link training. */
OUTP_DBG(&dp->outp, "training");
nvkm_dp_train_init(dp);
for (nr = dp->links; ret < 0 && nr; nr >>= 1) {
for (rate = 0; ret < 0 && rate < dp->rates; rate++) {
if (dp->rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) {
OUTP_DBG(outp, "training");
nvkm_dp_train_init(outp);
for (nr = outp->dp.links; ret < 0 && nr; nr >>= 1) {
for (rate = 0; ret < 0 && rate < outp->dp.rates; rate++) {
if (outp->dp.rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) {
/* Program selected link configuration. */
ior->dp.bw = dp->rate[rate].rate / 27000;
ior->dp.bw = outp->dp.rate[rate].rate / 27000;
ior->dp.nr = nr;
ret = nvkm_dp_train_links(dp, rate);
ret = nvkm_dp_train_links(outp, rate);
}
}
}
nvkm_dp_train_fini(dp);
nvkm_dp_train_fini(outp);
if (ret < 0)
OUTP_ERR(&dp->outp, "training failed");
OUTP_ERR(outp, "training failed");
else
OUTP_DBG(&dp->outp, "training done");
atomic_set(&dp->lt.done, 1);
OUTP_DBG(outp, "training done");
atomic_set(&outp->dp.lt.done, 1);
return ret;
}
void
nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior)
{
struct nvkm_dp *dp = nvkm_dp(outp);
/* Execute DisableLT script from DP Info Table. */
nvbios_init(&ior->disp->engine.subdev, dp->info.script[4],
init.outp = &dp->outp.info;
nvbios_init(&ior->disp->engine.subdev, outp->dp.info.script[4],
init.outp = &outp->info;
init.or = ior->id;
init.link = ior->arm.link;
);
@ -495,18 +488,15 @@ nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior)
static void
nvkm_dp_release(struct nvkm_outp *outp)
{
struct nvkm_dp *dp = nvkm_dp(outp);
/* Prevent link from being retrained if sink sends an IRQ. */
atomic_set(&dp->lt.done, 0);
dp->outp.ior->dp.nr = 0;
atomic_set(&outp->dp.lt.done, 0);
outp->ior->dp.nr = 0;
}
static int
nvkm_dp_acquire(struct nvkm_outp *outp)
{
struct nvkm_dp *dp = nvkm_dp(outp);
struct nvkm_ior *ior = dp->outp.ior;
struct nvkm_ior *ior = outp->ior;
struct nvkm_head *head;
bool retrain = true;
u32 datakbps = 0;
@ -515,10 +505,10 @@ nvkm_dp_acquire(struct nvkm_outp *outp)
u8 stat[3];
int ret, i;
mutex_lock(&dp->mutex);
mutex_lock(&outp->dp.mutex);
/* Check that link configuration meets current requirements. */
list_for_each_entry(head, &outp->disp->head, head) {
list_for_each_entry(head, &outp->disp->heads, head) {
if (ior->asy.head & (1 << head->id)) {
u32 khz = (head->asy.hz >> ior->asy.rgdiv) / 1000;
datakbps += khz * head->asy.or.depth;
@ -527,18 +517,17 @@ nvkm_dp_acquire(struct nvkm_outp *outp)
linkKBps = ior->dp.bw * 27000 * ior->dp.nr;
dataKBps = DIV_ROUND_UP(datakbps, 8);
OUTP_DBG(&dp->outp, "data %d KB/s link %d KB/s mst %d->%d",
dataKBps, linkKBps, ior->dp.mst, dp->lt.mst);
if (linkKBps < dataKBps || ior->dp.mst != dp->lt.mst) {
OUTP_DBG(&dp->outp, "link requirements changed");
OUTP_DBG(outp, "data %d KB/s link %d KB/s mst %d->%d",
dataKBps, linkKBps, ior->dp.mst, outp->dp.lt.mst);
if (linkKBps < dataKBps || ior->dp.mst != outp->dp.lt.mst) {
OUTP_DBG(outp, "link requirements changed");
goto done;
}
/* Check that link is still trained. */
ret = nvkm_rdaux(dp->aux, DPCD_LS02, stat, 3);
ret = nvkm_rdaux(outp->dp.aux, DPCD_LS02, stat, 3);
if (ret) {
OUTP_DBG(&dp->outp,
"failed to read link status, assuming no sink");
OUTP_DBG(outp, "failed to read link status, assuming no sink");
goto done;
}
@ -548,125 +537,126 @@ nvkm_dp_acquire(struct nvkm_outp *outp)
if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
!(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
OUTP_DBG(&dp->outp,
"lane %d not equalised", lane);
OUTP_DBG(outp, "lane %d not equalised", lane);
goto done;
}
}
retrain = false;
} else {
OUTP_DBG(&dp->outp, "no inter-lane alignment");
OUTP_DBG(outp, "no inter-lane alignment");
}
done:
if (retrain || !atomic_read(&dp->lt.done))
ret = nvkm_dp_train(dp, dataKBps);
mutex_unlock(&dp->mutex);
if (retrain || !atomic_read(&outp->dp.lt.done))
ret = nvkm_dp_train(outp, dataKBps);
mutex_unlock(&outp->dp.mutex);
return ret;
}
static bool
nvkm_dp_enable_supported_link_rates(struct nvkm_dp *dp)
nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp)
{
u8 sink_rates[DPCD_RC10_SUPPORTED_LINK_RATES__SIZE];
int i, j, k;
if (dp->outp.conn->info.type != DCB_CONNECTOR_eDP ||
dp->dpcd[DPCD_RC00_DPCD_REV] < 0x13 ||
nvkm_rdaux(dp->aux, DPCD_RC10_SUPPORTED_LINK_RATES(0), sink_rates, sizeof(sink_rates)))
if (outp->conn->info.type != DCB_CONNECTOR_eDP ||
outp->dp.dpcd[DPCD_RC00_DPCD_REV] < 0x13 ||
nvkm_rdaux(outp->dp.aux, DPCD_RC10_SUPPORTED_LINK_RATES(0),
sink_rates, sizeof(sink_rates)))
return false;
for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) {
const u32 rate = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10;
if (!rate || WARN_ON(dp->rates == ARRAY_SIZE(dp->rate)))
if (!rate || WARN_ON(outp->dp.rates == ARRAY_SIZE(outp->dp.rate)))
break;
if (rate > dp->outp.info.dpconf.link_bw * 27000) {
OUTP_DBG(&dp->outp, "rate %d !outp", rate);
if (rate > outp->info.dpconf.link_bw * 27000) {
OUTP_DBG(outp, "rate %d !outp", rate);
continue;
}
for (j = 0; j < dp->rates; j++) {
if (rate > dp->rate[j].rate) {
for (k = dp->rates; k > j; k--)
dp->rate[k] = dp->rate[k - 1];
for (j = 0; j < outp->dp.rates; j++) {
if (rate > outp->dp.rate[j].rate) {
for (k = outp->dp.rates; k > j; k--)
outp->dp.rate[k] = outp->dp.rate[k - 1];
break;
}
}
dp->rate[j].dpcd = i / 2;
dp->rate[j].rate = rate;
dp->rates++;
outp->dp.rate[j].dpcd = i / 2;
outp->dp.rate[j].rate = rate;
outp->dp.rates++;
}
for (i = 0; i < dp->rates; i++)
OUTP_DBG(&dp->outp, "link_rate[%d] = %d", dp->rate[i].dpcd, dp->rate[i].rate);
for (i = 0; i < outp->dp.rates; i++)
OUTP_DBG(outp, "link_rate[%d] = %d", outp->dp.rate[i].dpcd, outp->dp.rate[i].rate);
return dp->rates != 0;
return outp->dp.rates != 0;
}
static bool
nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
nvkm_dp_enable(struct nvkm_outp *outp, bool enable)
{
struct nvkm_i2c_aux *aux = dp->aux;
struct nvkm_i2c_aux *aux = outp->dp.aux;
if (enable) {
if (!dp->present) {
OUTP_DBG(&dp->outp, "aux power -> always");
if (!outp->dp.present) {
OUTP_DBG(outp, "aux power -> always");
nvkm_i2c_aux_monitor(aux, true);
dp->present = true;
outp->dp.present = true;
}
/* Detect any LTTPRs before reading DPCD receiver caps. */
if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, dp->lttpr, sizeof(dp->lttpr)) &&
dp->lttpr[0] >= 0x14 && dp->lttpr[2]) {
switch (dp->lttpr[2]) {
case 0x80: dp->lttprs = 1; break;
case 0x40: dp->lttprs = 2; break;
case 0x20: dp->lttprs = 3; break;
case 0x10: dp->lttprs = 4; break;
case 0x08: dp->lttprs = 5; break;
case 0x04: dp->lttprs = 6; break;
case 0x02: dp->lttprs = 7; break;
case 0x01: dp->lttprs = 8; break;
if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, outp->dp.lttpr, sizeof(outp->dp.lttpr)) &&
outp->dp.lttpr[0] >= 0x14 && outp->dp.lttpr[2]) {
switch (outp->dp.lttpr[2]) {
case 0x80: outp->dp.lttprs = 1; break;
case 0x40: outp->dp.lttprs = 2; break;
case 0x20: outp->dp.lttprs = 3; break;
case 0x10: outp->dp.lttprs = 4; break;
case 0x08: outp->dp.lttprs = 5; break;
case 0x04: outp->dp.lttprs = 6; break;
case 0x02: outp->dp.lttprs = 7; break;
case 0x01: outp->dp.lttprs = 8; break;
default:
/* Unknown LTTPR count, we'll switch to transparent mode. */
WARN_ON(1);
dp->lttprs = 0;
outp->dp.lttprs = 0;
break;
}
} else {
/* No LTTPR support, or zero LTTPR count - don't touch it at all. */
memset(dp->lttpr, 0x00, sizeof(dp->lttpr));
memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr));
}
if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, sizeof(dp->dpcd))) {
if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, sizeof(outp->dp.dpcd))) {
const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 };
const u8 *rate;
int rate_max;
dp->rates = 0;
dp->links = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT;
dp->links = min(dp->links, dp->outp.info.dpconf.link_nr);
if (dp->lttprs && dp->lttpr[4])
dp->links = min_t(int, dp->links, dp->lttpr[4]);
outp->dp.rates = 0;
outp->dp.links = outp->dp.dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT;
outp->dp.links = min(outp->dp.links, outp->info.dpconf.link_nr);
if (outp->dp.lttprs && outp->dp.lttpr[4])
outp->dp.links = min_t(int, outp->dp.links, outp->dp.lttpr[4]);
rate_max = dp->dpcd[DPCD_RC01_MAX_LINK_RATE];
rate_max = min(rate_max, dp->outp.info.dpconf.link_bw);
if (dp->lttprs && dp->lttpr[1])
rate_max = min_t(int, rate_max, dp->lttpr[1]);
rate_max = outp->dp.dpcd[DPCD_RC01_MAX_LINK_RATE];
rate_max = min(rate_max, outp->info.dpconf.link_bw);
if (outp->dp.lttprs && outp->dp.lttpr[1])
rate_max = min_t(int, rate_max, outp->dp.lttpr[1]);
if (!nvkm_dp_enable_supported_link_rates(dp)) {
if (!nvkm_dp_enable_supported_link_rates(outp)) {
for (rate = rates; *rate; rate++) {
if (*rate <= rate_max) {
if (WARN_ON(dp->rates == ARRAY_SIZE(dp->rate)))
break;
if (*rate > rate_max)
continue;
dp->rate[dp->rates].dpcd = -1;
dp->rate[dp->rates].rate = *rate * 27000;
dp->rates++;
}
if (WARN_ON(outp->dp.rates == ARRAY_SIZE(outp->dp.rate)))
break;
outp->dp.rate[outp->dp.rates].dpcd = -1;
outp->dp.rate[outp->dp.rates].rate = *rate * 27000;
outp->dp.rates++;
}
}
@ -674,13 +664,13 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable)
}
}
if (dp->present) {
OUTP_DBG(&dp->outp, "aux power -> demand");
if (outp->dp.present) {
OUTP_DBG(outp, "aux power -> demand");
nvkm_i2c_aux_monitor(aux, false);
dp->present = false;
outp->dp.present = false;
}
atomic_set(&dp->lt.done, 0);
atomic_set(&outp->dp.lt.done, 0);
return false;
}
@ -688,18 +678,18 @@ static int
nvkm_dp_hpd(struct nvkm_notify *notify)
{
const struct nvkm_i2c_ntfy_rep *line = notify->data;
struct nvkm_dp *dp = container_of(notify, typeof(*dp), hpd);
struct nvkm_conn *conn = dp->outp.conn;
struct nvkm_disp *disp = dp->outp.disp;
struct nvkm_outp *outp = container_of(notify, typeof(*outp), dp.hpd);
struct nvkm_conn *conn = outp->conn;
struct nvkm_disp *disp = outp->disp;
struct nvif_notify_conn_rep_v0 rep = {};
OUTP_DBG(&dp->outp, "HPD: %d", line->mask);
OUTP_DBG(outp, "HPD: %d", line->mask);
if (line->mask & NVKM_I2C_IRQ) {
if (atomic_read(&dp->lt.done))
dp->outp.func->acquire(&dp->outp);
if (atomic_read(&outp->dp.lt.done))
outp->func->acquire(outp);
rep.mask |= NVIF_NOTIFY_CONN_V0_IRQ;
} else {
nvkm_dp_enable(dp, true);
nvkm_dp_enable(outp, true);
}
if (line->mask & NVKM_I2C_UNPLUG)
@ -714,24 +704,22 @@ nvkm_dp_hpd(struct nvkm_notify *notify)
static void
nvkm_dp_fini(struct nvkm_outp *outp)
{
struct nvkm_dp *dp = nvkm_dp(outp);
nvkm_notify_put(&dp->hpd);
nvkm_dp_enable(dp, false);
nvkm_notify_put(&outp->dp.hpd);
nvkm_dp_enable(outp, false);
}
static void
nvkm_dp_init(struct nvkm_outp *outp)
{
struct nvkm_gpio *gpio = outp->disp->engine.subdev.device->gpio;
struct nvkm_dp *dp = nvkm_dp(outp);
nvkm_notify_put(&dp->outp.conn->hpd);
nvkm_notify_put(&outp->conn->hpd);
/* eDP panels need powering on by us (if the VBIOS doesn't default it
* to on) before doing any AUX channel transactions. LVDS panel power
* is handled by the SOR itself, and not required for LVDS DDC.
*/
if (dp->outp.conn->info.type == DCB_CONNECTOR_eDP) {
if (outp->conn->info.type == DCB_CONNECTOR_eDP) {
int power = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
if (power == 0)
nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
@ -748,21 +736,20 @@ nvkm_dp_init(struct nvkm_outp *outp)
/* If the eDP panel can't be detected, we need to restore
* the panel power GPIO to avoid breaking another output.
*/
if (!nvkm_dp_enable(dp, true) && power == 0)
if (!nvkm_dp_enable(outp, true) && power == 0)
nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 0);
} else {
nvkm_dp_enable(dp, true);
nvkm_dp_enable(outp, true);
}
nvkm_notify_get(&dp->hpd);
nvkm_notify_get(&outp->dp.hpd);
}
static void *
nvkm_dp_dtor(struct nvkm_outp *outp)
{
struct nvkm_dp *dp = nvkm_dp(outp);
nvkm_notify_fini(&dp->hpd);
return dp;
nvkm_notify_fini(&outp->dp.hpd);
return outp;
}
static const struct nvkm_outp_func
@ -775,75 +762,57 @@ nvkm_dp_func = {
.disable = nvkm_dp_disable,
};
static int
nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
struct nvkm_i2c_aux *aux, struct nvkm_dp *dp)
int
nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct nvkm_outp **poutp)
{
struct nvkm_device *device = disp->engine.subdev.device;
struct nvkm_bios *bios = device->bios;
struct nvkm_i2c *i2c = device->i2c;
struct nvkm_outp *outp;
u8 hdr, cnt, len;
u32 data;
int ret;
ret = nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp);
ret = nvkm_outp_new_(&nvkm_dp_func, disp, index, dcbE, poutp);
outp = *poutp;
if (ret)
return ret;
dp->aux = aux;
if (!dp->aux) {
OUTP_ERR(&dp->outp, "no aux");
if (dcbE->location == 0)
outp->dp.aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_CCB(dcbE->i2c_index));
else
outp->dp.aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev));
if (!outp->dp.aux) {
OUTP_ERR(outp, "no aux");
return -EINVAL;
}
/* bios data is not optional */
data = nvbios_dpout_match(bios, dp->outp.info.hasht,
dp->outp.info.hashm, &dp->version,
&hdr, &cnt, &len, &dp->info);
data = nvbios_dpout_match(bios, outp->info.hasht, outp->info.hashm,
&outp->dp.version, &hdr, &cnt, &len, &outp->dp.info);
if (!data) {
OUTP_ERR(&dp->outp, "no bios dp data");
OUTP_ERR(outp, "no bios dp data");
return -EINVAL;
}
OUTP_DBG(&dp->outp, "bios dp %02x %02x %02x %02x",
dp->version, hdr, cnt, len);
OUTP_DBG(outp, "bios dp %02x %02x %02x %02x", outp->dp.version, hdr, cnt, len);
/* hotplug detect, replaces gpio-based mechanism with aux events */
ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_hpd, true,
&(struct nvkm_i2c_ntfy_req) {
.mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG |
NVKM_I2C_IRQ,
.port = dp->aux->id,
.port = outp->dp.aux->id,
},
sizeof(struct nvkm_i2c_ntfy_req),
sizeof(struct nvkm_i2c_ntfy_rep),
&dp->hpd);
&outp->dp.hpd);
if (ret) {
OUTP_ERR(&dp->outp, "error monitoring aux hpd: %d", ret);
OUTP_ERR(outp, "error monitoring aux hpd: %d", ret);
return ret;
}
mutex_init(&dp->mutex);
atomic_set(&dp->lt.done, 0);
mutex_init(&outp->dp.mutex);
atomic_set(&outp->dp.lt.done, 0);
return 0;
}
int
nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE,
struct nvkm_outp **poutp)
{
struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
struct nvkm_i2c_aux *aux;
struct nvkm_dp *dp;
if (dcbE->location == 0)
aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_CCB(dcbE->i2c_index));
else
aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev));
if (!(dp = kzalloc(sizeof(*dp), GFP_KERNEL)))
return -ENOMEM;
*poutp = &dp->outp;
return nvkm_dp_ctor(disp, index, dcbE, aux, dp);
}

View file

@ -1,41 +1,8 @@
/* SPDX-License-Identifier: MIT */
#ifndef __NVKM_DISP_DP_H__
#define __NVKM_DISP_DP_H__
#define nvkm_dp(p) container_of((p), struct nvkm_dp, outp)
#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 *,
struct nvkm_outp **);
void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *);

View file

@ -21,28 +21,307 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "hdmi.h"
#include "head.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 = {
.oneinit = nv50_disp_oneinit,
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super,
.root = &g84_disp_root_oclass,
.uevent = &nv50_disp_chan_uevent,
.head = { .cnt = nv50_head_cnt, .new = nv50_head_new },
.dac = { .cnt = nv50_dac_cnt, .new = nv50_dac_new },
.sor = { .cnt = nv50_sor_cnt, .new = g84_sor_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
g84_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&g84_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&g84_disp, device, type, inst, pdisp);
}

View file

@ -21,28 +21,357 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
#include <subdev/timer.h>
#include <nvif/class.h>
void
g94_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
nvkm_mask(device, 0x61c128 + loff, 0x0000003f, watermark);
}
void
g94_sor_dp_activesym(struct nvkm_ior *sor, int head,
u8 TU, u8 VTUa, u8 VTUf, u8 VTUi)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
nvkm_mask(device, 0x61c10c + loff, 0x000001fc, TU << 2);
nvkm_mask(device, 0x61c128 + loff, 0x010f7f00, VTUa << 24 | VTUf << 16 | VTUi << 8);
}
void
g94_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, h);
nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, v);
}
void
g94_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
const u32 shift = sor->func->dp->lanes[ln] * 8;
u32 data[3];
data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
data[2] = nvkm_rd32(device, 0x61c130 + loff);
if ((data[2] & 0x0000ff00) < (pu << 8) || ln == 0)
data[2] = (data[2] & ~0x0000ff00) | (pu << 8);
nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift));
nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift));
nvkm_wr32(device, 0x61c130 + loff, data[2]);
}
void
g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
u32 data;
switch (pattern) {
case 0: data = 0x00001000; break;
case 1: data = 0x01000000; break;
case 2: data = 0x02000000; break;
default:
WARN_ON(1);
return;
}
nvkm_mask(device, 0x61c10c + loff, 0x0f001000, data);
}
void
g94_sor_dp_power(struct nvkm_ior *sor, int nr)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
const u32 loff = nv50_sor_link(sor);
u32 mask = 0, i;
for (i = 0; i < nr; i++)
mask |= 1 << sor->func->dp->lanes[i];
nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask);
nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000))
break;
);
}
int
g94_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;
dpctrl |= ((1 << sor->dp.nr) - 1) << 16;
if (sor->dp.ef)
dpctrl |= 0x00004000;
if (sor->dp.bw > 0x06)
clksor |= 0x00040000;
nvkm_mask(device, 0x614300 + soff, 0x000c0000, clksor);
nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl);
return 0;
}
const struct nvkm_ior_func_dp
g94_sor_dp = {
.lanes = { 2, 1, 0, 3},
.links = g94_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = g94_sor_dp_pattern,
.drive = g94_sor_dp_drive,
.audio_sym = g94_sor_dp_audio_sym,
.activesym = g94_sor_dp_activesym,
.watermark = g94_sor_dp_watermark,
};
static bool
g94_sor_war_needed(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
if (sor->asy.proto == TMDS) {
switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) {
case 0x00000000:
case 0x00030000:
return true;
default:
break;
}
}
return false;
}
static void
g94_sor_war_update_sppll1(struct nvkm_disp *disp)
{
struct nvkm_device *device = disp->engine.subdev.device;
struct nvkm_ior *ior;
bool used = false;
u32 clksor;
list_for_each_entry(ior, &disp->iors, head) {
if (ior->type != SOR)
continue;
clksor = nvkm_rd32(device, 0x614300 + nv50_ior_base(ior));
switch (clksor & 0x03000000) {
case 0x02000000:
case 0x03000000:
used = true;
break;
default:
break;
}
}
if (used)
return;
nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000);
}
static void
g94_sor_war_3(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
u32 sorpwr;
if (!g94_sor_war_needed(sor))
return;
sorpwr = nvkm_rd32(device, 0x61c004 + soff);
if (sorpwr & 0x00000001) {
u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
u32 pd_pc = (seqctl & 0x00000f00) >> 8;
u32 pu_pc = seqctl & 0x0000000f;
nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x1f008000);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
break;
);
nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000))
break;
);
nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x00002000);
nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f000000);
}
nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x00000000);
if (sorpwr & 0x00000001)
nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001);
g94_sor_war_update_sppll1(sor->disp);
}
static void
g94_sor_war_2(struct nvkm_ior *sor)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
if (!g94_sor_war_needed(sor))
return;
nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000);
nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x03000000);
nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000001);
nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x00000000);
nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x14000000);
nvkm_usec(device, 400, NVKM_DELAY);
nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x00000000);
nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x01000000);
if (nvkm_rd32(device, 0x61c004 + soff) & 0x00000001) {
u32 seqctl = nvkm_rd32(device, 0x61c030 + soff);
u32 pu_pc = seqctl & 0x0000000f;
nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000);
}
}
void
g94_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 coff = sor->id * 8 + (state == &sor->arm) * 4;
u32 ctrl = nvkm_rd32(device, 0x610794 + coff);
state->proto_evo = (ctrl & 0x00000f00) >> 8;
switch (state->proto_evo) {
case 0: state->proto = LVDS; state->link = 1; break;
case 1: state->proto = TMDS; state->link = 1; break;
case 2: state->proto = TMDS; state->link = 2; break;
case 5: state->proto = TMDS; state->link = 3; break;
case 8: state->proto = DP; state->link = 1; break;
case 9: state->proto = DP; state->link = 2; break;
default:
state->proto = UNKNOWN;
break;
}
state->head = ctrl & 0x00000003;
nv50_pior_depth(sor, state, ctrl);
}
static const struct nvkm_ior_func
g94_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
.war_2 = g94_sor_war_2,
.war_3 = g94_sor_war_3,
.dp = &g94_sor_dp,
};
static int
g94_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&g94_sor, disp, SOR, id, false);
}
int
g94_sor_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = (nvkm_rd32(device, 0x610184) & 0x0f000000) >> 24;
return 4;
}
static const struct nvkm_disp_mthd_list
g94_disp_core_mthd_sor = {
.mthd = 0x0040,
.addr = 0x000008,
.data = {
{ 0x0600, 0x610794 },
{}
}
};
const struct nvkm_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 },
{}
}
};
const struct nvkm_disp_chan_user
g94_disp_core = {
.func = &nv50_disp_core_func,
.ctrl = 0,
.user = 0,
.mthd = &g94_disp_core_mthd,
};
static const struct nvkm_disp_func
g94_disp = {
.oneinit = nv50_disp_oneinit,
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super,
.root = &g94_disp_root_oclass,
.uevent = &nv50_disp_chan_uevent,
.head = { .cnt = nv50_head_cnt, .new = nv50_head_new },
.dac = { .cnt = nv50_dac_cnt, .new = nv50_dac_new },
.sor = { .cnt = g94_sor_cnt, .new = g94_sor_new },
.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
.root = { 0,0,GT206_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,GT200_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, & g84_disp_base },
{{0,0,GT206_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, & g94_disp_core },
{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, &gt200_disp_ovly },
{}
},
};
int
g94_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&g94_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&g94_disp, device, type, inst, pdisp);
}

View file

@ -19,29 +19,135 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "head.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 = {
.oneinit = nv50_disp_oneinit,
.init = tu102_disp_init,
.fini = gv100_disp_fini,
.intr = gv100_disp_intr,
.uevent = &gv100_disp_chan_uevent,
.super = gv100_disp_super,
.root = &ga102_disp_root_oclass,
.uevent = &gv100_disp_chan_uevent,
.wndw = { .cnt = gv100_disp_wndw_cnt },
.head = { .cnt = gv100_head_cnt, .new = gv100_head_new },
.sor = { .cnt = gv100_sor_cnt, .new = ga102_sor_new },
.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
ga102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&ga102_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&ga102_disp, device, type, inst, pdisp);
}

File diff suppressed because it is too large Load diff

View file

@ -21,28 +21,291 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "hdmi.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
#include <nvif/class.h>
void
gk104_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 |
max_ac_packet << 16 |
rekey;
const u32 hoff = head * 0x800;
const u32 hdmi = head * 0x400;
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, 0x616798 + hoff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000000);
nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x690008 + hdmi, avi_infoframe.header);
nvkm_wr32(device, 0x69000c + hdmi, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x690010 + hdmi, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x690014 + hdmi, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x690018 + hdmi, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001);
}
/* GENERIC(?) / Vendor InfoFrame? */
nvkm_mask(device, 0x690100 + hdmi, 0x00010001, 0x00000000);
if (vendor_size) {
nvkm_wr32(device, 0x690108 + hdmi, vendor_infoframe.header);
nvkm_wr32(device, 0x69010c + hdmi, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x690110 + hdmi, vendor_infoframe.subpack0_high);
/* Is there a second (or further?) set of subpack registers here? */
nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000001);
}
/* ??? InfoFrame? */
nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x6900cc + hdmi, 0x00000010);
nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
/* ??? */
nvkm_wr32(device, 0x690080 + hdmi, 0x82000000);
/* HDMI_CTRL */
nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl);
}
static const struct nvkm_ior_func
gk104_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
.hdmi = {
.ctrl = gk104_sor_hdmi_ctrl,
},
.dp = &gf119_sor_dp,
.hda = &gf119_sor_hda,
};
int
gk104_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&gk104_sor, disp, SOR, id, true);
}
static const struct nvkm_disp_mthd_list
gk104_disp_ovly_mthd_base = {
.mthd = 0x0000,
.data = {
{ 0x0080, 0x665080 },
{ 0x0084, 0x665084 },
{ 0x0088, 0x665088 },
{ 0x008c, 0x66508c },
{ 0x0090, 0x665090 },
{ 0x0094, 0x665094 },
{ 0x00a0, 0x6650a0 },
{ 0x00a4, 0x6650a4 },
{ 0x00b0, 0x6650b0 },
{ 0x00b4, 0x6650b4 },
{ 0x00b8, 0x6650b8 },
{ 0x00c0, 0x6650c0 },
{ 0x00c4, 0x6650c4 },
{ 0x00e0, 0x6650e0 },
{ 0x00e4, 0x6650e4 },
{ 0x00e8, 0x6650e8 },
{ 0x0100, 0x665100 },
{ 0x0104, 0x665104 },
{ 0x0108, 0x665108 },
{ 0x010c, 0x66510c },
{ 0x0110, 0x665110 },
{ 0x0118, 0x665118 },
{ 0x011c, 0x66511c },
{ 0x0120, 0x665120 },
{ 0x0124, 0x665124 },
{ 0x0130, 0x665130 },
{ 0x0134, 0x665134 },
{ 0x0138, 0x665138 },
{ 0x013c, 0x66513c },
{ 0x0140, 0x665140 },
{ 0x0144, 0x665144 },
{ 0x0148, 0x665148 },
{ 0x014c, 0x66514c },
{ 0x0150, 0x665150 },
{ 0x0154, 0x665154 },
{ 0x0158, 0x665158 },
{ 0x015c, 0x66515c },
{ 0x0160, 0x665160 },
{ 0x0164, 0x665164 },
{ 0x0168, 0x665168 },
{ 0x016c, 0x66516c },
{ 0x0400, 0x665400 },
{ 0x0404, 0x665404 },
{ 0x0408, 0x665408 },
{ 0x040c, 0x66540c },
{ 0x0410, 0x665410 },
{}
}
};
const struct nvkm_disp_chan_mthd
gk104_disp_ovly_mthd = {
.name = "Overlay",
.addr = 0x001000,
.prev = -0x020000,
.data = {
{ "Global", 1, &gk104_disp_ovly_mthd_base },
{}
}
};
const struct nvkm_disp_chan_user
gk104_disp_ovly = {
.func = &gf119_disp_dmac_func,
.ctrl = 5,
.user = 5,
.mthd = &gk104_disp_ovly_mthd,
};
static const struct nvkm_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 nvkm_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 },
{}
}
};
const struct nvkm_disp_chan_user
gk104_disp_core = {
.func = &gf119_disp_core_func,
.ctrl = 0,
.user = 0,
.mthd = &gk104_disp_core_mthd,
};
static const struct nvkm_disp_func
gk104_disp = {
.oneinit = nv50_disp_oneinit,
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_super,
.root = &gk104_disp_root_oclass,
.uevent = &gf119_disp_chan_uevent,
.head = { .cnt = gf119_head_cnt, .new = gf119_head_new },
.dac = { .cnt = gf119_dac_cnt, .new = gf119_dac_new },
.sor = { .cnt = gf119_sor_cnt, .new = gk104_sor_new },
.root = { 0,0,GK104_DISP },
.user = {
{{0,0,GK104_DISP_CURSOR }, nvkm_disp_chan_new, &gf119_disp_curs },
{{0,0,GK104_DISP_OVERLAY }, nvkm_disp_chan_new, &gf119_disp_oimm },
{{0,0,GK104_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, &gf119_disp_base },
{{0,0,GK104_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gk104_disp_core },
{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
{}
},
};
int
gk104_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gk104_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gk104_disp, device, type, inst, pdisp);
}

View file

@ -21,28 +21,39 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
#include <nvif/class.h>
static const struct nvkm_disp_func
gk110_disp = {
.oneinit = nv50_disp_oneinit,
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_super,
.root = &gk110_disp_root_oclass,
.uevent = &gf119_disp_chan_uevent,
.head = { .cnt = gf119_head_cnt, .new = gf119_head_new },
.dac = { .cnt = gf119_dac_cnt, .new = gf119_dac_new },
.sor = { .cnt = gf119_sor_cnt, .new = gk104_sor_new },
.root = { 0,0,GK110_DISP },
.user = {
{{0,0,GK104_DISP_CURSOR }, nvkm_disp_chan_new, &gf119_disp_curs },
{{0,0,GK104_DISP_OVERLAY }, nvkm_disp_chan_new, &gf119_disp_oimm },
{{0,0,GK110_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, &gf119_disp_base },
{{0,0,GK110_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gk104_disp_core },
{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
{}
},
};
int
gk110_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gk110_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gk110_disp, device, type, inst, pdisp);
}

View file

@ -21,28 +21,94 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
#include <nvif/class.h>
void
gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
u32 mask = 0x1f1f1f1f, data;
switch (pattern) {
case 0: data = 0x10101010; break;
case 1: data = 0x01010101; break;
case 2: data = 0x02020202; break;
case 3: data = 0x03030303; break;
case 4: data = 0x1b1b1b1b; break;
default:
WARN_ON(1);
return;
}
if (sor->asy.link & 1)
nvkm_mask(device, 0x61c110 + soff, mask, data);
else
nvkm_mask(device, 0x61c12c + soff, mask, data);
}
static const struct nvkm_ior_func_dp
gm107_sor_dp = {
.lanes = { 0, 1, 2, 3 },
.links = gf119_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gf119_sor_dp_drive,
.vcpi = gf119_sor_dp_vcpi,
.audio = gf119_sor_dp_audio,
.audio_sym = gf119_sor_dp_audio_sym,
.watermark = gf119_sor_dp_watermark,
};
static const struct nvkm_ior_func
gm107_sor = {
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
.hdmi = {
.ctrl = gk104_sor_hdmi_ctrl,
},
.dp = &gm107_sor_dp,
.hda = &gf119_sor_hda,
};
static int
gm107_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&gm107_sor, disp, SOR, id, true);
}
static const struct nvkm_disp_func
gm107_disp = {
.oneinit = nv50_disp_oneinit,
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_super,
.root = &gm107_disp_root_oclass,
.uevent = &gf119_disp_chan_uevent,
.head = { .cnt = gf119_head_cnt, .new = gf119_head_new },
.dac = { .cnt = gf119_dac_cnt, .new = gf119_dac_new },
.sor = { .cnt = gf119_sor_cnt, .new = gm107_sor_new },
.root = { 0,0,GM107_DISP },
.user = {
{{0,0,GK104_DISP_CURSOR }, nvkm_disp_chan_new, &gf119_disp_curs },
{{0,0,GK104_DISP_OVERLAY }, nvkm_disp_chan_new, &gf119_disp_oimm },
{{0,0,GK110_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, &gf119_disp_base },
{{0,0,GM107_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gk104_disp_core },
{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
{}
},
};
int
gm107_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gm107_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gm107_disp, device, type, inst, pdisp);
}

View file

@ -21,28 +21,162 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "hdmi.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
#include "outp.h"
static const struct nv50_disp_func
#include <nvif/class.h>
void
gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 loff = nv50_sor_link(sor);
const u32 shift = sor->func->dp->lanes[ln] * 8;
u32 data[4];
pu &= 0x0f;
data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift);
data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift);
data[2] = nvkm_rd32(device, 0x61c130 + loff);
if ((data[2] & 0x00000f00) < (pu << 8) || ln == 0)
data[2] = (data[2] & ~0x00000f00) | (pu << 8);
nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift));
nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift));
nvkm_wr32(device, 0x61c130 + loff, data[2]);
data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift);
nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift));
}
const struct nvkm_ior_func_dp
gm200_sor_dp = {
.lanes = { 0, 1, 2, 3 },
.links = gf119_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = gm107_sor_dp_pattern,
.drive = gm200_sor_dp_drive,
.vcpi = gf119_sor_dp_vcpi,
.audio = gf119_sor_dp_audio,
.audio_sym = gf119_sor_dp_audio_sym,
.watermark = gf119_sor_dp_watermark,
};
void
gm200_sor_hdmi_scdc(struct nvkm_ior *ior, u8 scdc)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(ior);
const u32 ctrl = scdc & 0x3;
nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
ior->tmds.high_speed = !!(scdc & 0x2);
}
void
gm200_sor_route_set(struct nvkm_outp *outp, struct nvkm_ior *ior)
{
struct nvkm_device *device = outp->disp->engine.subdev.device;
const u32 moff = __ffs(outp->info.or) * 0x100;
const u32 sor = ior ? ior->id + 1 : 0;
u32 link = ior ? (ior->asy.link == 2) : 0;
if (outp->info.sorconf.link & 1) {
nvkm_mask(device, 0x612308 + moff, 0x0000001f, link << 4 | sor);
link++;
}
if (outp->info.sorconf.link & 2)
nvkm_mask(device, 0x612388 + moff, 0x0000001f, link << 4 | sor);
}
int
gm200_sor_route_get(struct nvkm_outp *outp, int *link)
{
struct nvkm_device *device = outp->disp->engine.subdev.device;
const int sublinks = outp->info.sorconf.link;
int lnk[2], sor[2], m, s;
for (*link = 0, m = __ffs(outp->info.or) * 2, s = 0; s < 2; m++, s++) {
if (sublinks & BIT(s)) {
u32 data = nvkm_rd32(device, 0x612308 + (m * 0x80));
lnk[s] = (data & 0x00000010) >> 4;
sor[s] = (data & 0x0000000f);
if (!sor[s])
return -1;
*link |= lnk[s];
}
}
if (sublinks == 3) {
if (sor[0] != sor[1] || WARN_ON(lnk[0] || !lnk[1]))
return -1;
}
return ((sublinks & 1) ? sor[0] : sor[1]) - 1;
}
static const struct nvkm_ior_func
gm200_sor = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
},
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
.hdmi = {
.ctrl = gk104_sor_hdmi_ctrl,
.scdc = gm200_sor_hdmi_scdc,
},
.dp = &gm200_sor_dp,
.hda = &gf119_sor_hda,
};
static int
gm200_sor_new(struct nvkm_disp *disp, int id)
{
struct nvkm_device *device = disp->engine.subdev.device;
u32 hda;
if (!((hda = nvkm_rd32(device, 0x08a15c)) & 0x40000000))
hda = nvkm_rd32(device, 0x101034);
return nvkm_ior_new_(&gm200_sor, disp, SOR, id, hda & BIT(id));
}
static const struct nvkm_disp_func
gm200_disp = {
.oneinit = nv50_disp_oneinit,
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_super,
.root = &gm200_disp_root_oclass,
.uevent = &gf119_disp_chan_uevent,
.head = { .cnt = gf119_head_cnt, .new = gf119_head_new },
.dac = { .cnt = gf119_dac_cnt, .new = gf119_dac_new },
.sor = { .cnt = gf119_sor_cnt, .new = gm200_sor_new },
.root = { 0,0,GM200_DISP },
.user = {
{{0,0,GK104_DISP_CURSOR }, nvkm_disp_chan_new, &gf119_disp_curs },
{{0,0,GK104_DISP_OVERLAY }, nvkm_disp_chan_new, &gf119_disp_oimm },
{{0,0,GK110_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, &gf119_disp_base },
{{0,0,GM200_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gk104_disp_core },
{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
{}
},
};
int
gm200_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gm200_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gm200_disp, device, type, inst, pdisp);
}

View file

@ -21,27 +21,67 @@
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
#include <nvif/class.h>
static const struct nvkm_ior_func
gp100_sor = {
.route = {
.get = gm200_sor_route_get,
.set = gm200_sor_route_set,
},
.state = gf119_sor_state,
.power = nv50_sor_power,
.clock = gf119_sor_clock,
.hdmi = {
.ctrl = gk104_sor_hdmi_ctrl,
.scdc = gm200_sor_hdmi_scdc,
},
.dp = &gm200_sor_dp,
.hda = &gf119_sor_hda,
};
int
gp100_sor_new(struct nvkm_disp *disp, int id)
{
struct nvkm_device *device = disp->engine.subdev.device;
u32 hda;
if (!((hda = nvkm_rd32(device, 0x08a15c)) & 0x40000000))
hda = nvkm_rd32(device, 0x10ebb0) >> 8;
return nvkm_ior_new_(&gp100_sor, disp, SOR, id, hda & BIT(id));
}
static const struct nvkm_disp_func
gp100_disp = {
.oneinit = nv50_disp_oneinit,
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_super,
.root = &gp100_disp_root_oclass,
.uevent = &gf119_disp_chan_uevent,
.head = { .cnt = gf119_head_cnt, .new = gf119_head_new },
.sor = { .cnt = gf119_sor_cnt, .new = gp100_sor_new },
.root = { 0,0,GP100_DISP },
.user = {
{{0,0,GK104_DISP_CURSOR }, nvkm_disp_chan_new, &gf119_disp_curs },
{{0,0,GK104_DISP_OVERLAY }, nvkm_disp_chan_new, &gf119_disp_oimm },
{{0,0,GK110_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, &gf119_disp_base },
{{0,0,GP100_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gk104_disp_core },
{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
{}
},
};
int
gp100_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gp100_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gp100_disp, device, type, inst, pdisp);
}

View file

@ -21,16 +21,133 @@
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "head.h"
#include "ior.h"
#include "channv50.h"
#include "rootnv50.h"
#include <subdev/timer.h>
#include <nvif/class.h>
static int
gp102_disp_dmac_init(struct nvkm_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->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 nvkm_disp_chan_func
gp102_disp_dmac_func = {
.push = nv50_disp_dmac_push,
.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,
};
static const struct nvkm_disp_chan_user
gp102_disp_curs = {
.func = &gf119_disp_pioc_func,
.ctrl = 13,
.user = 17,
};
static const struct nvkm_disp_chan_user
gp102_disp_oimm = {
.func = &gf119_disp_pioc_func,
.ctrl = 9,
.user = 13,
};
static const struct nvkm_disp_chan_user
gp102_disp_ovly = {
.func = &gp102_disp_dmac_func,
.ctrl = 5,
.user = 5,
.mthd = &gk104_disp_ovly_mthd,
};
static const struct nvkm_disp_chan_user
gp102_disp_base = {
.func = &gp102_disp_dmac_func,
.ctrl = 1,
.user = 1,
.mthd = &gf119_disp_base_mthd,
};
static int
gp102_disp_core_init(struct nvkm_disp_chan *chan)
{
struct nvkm_subdev *subdev = &chan->disp->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 nvkm_disp_chan_func
gp102_disp_core_func = {
.push = nv50_disp_dmac_push,
.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,
};
static const struct nvkm_disp_chan_user
gp102_disp_core = {
.func = &gp102_disp_core_func,
.ctrl = 0,
.user = 0,
.mthd = &gk104_disp_core_mthd,
};
static void
gp102_disp_intr_error(struct nv50_disp *disp, int chid)
gp102_disp_intr_error(struct nvkm_disp *disp, int chid)
{
struct nvkm_subdev *subdev = &disp->base.engine.subdev;
struct nvkm_subdev *subdev = &disp->engine.subdev;
struct nvkm_device *device = subdev->device;
u32 mthd = nvkm_rd32(device, 0x6111f0 + (chid * 12));
u32 data = nvkm_rd32(device, 0x6111f4 + (chid * 12));
@ -53,22 +170,31 @@ gp102_disp_intr_error(struct nv50_disp *disp, int chid)
nvkm_wr32(device, 0x6111f0 + (chid * 12), 0x90000000);
}
static const struct nv50_disp_func
static const struct nvkm_disp_func
gp102_disp = {
.oneinit = nv50_disp_oneinit,
.init = gf119_disp_init,
.fini = gf119_disp_fini,
.intr = gf119_disp_intr,
.intr_error = gp102_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_super,
.root = &gp102_disp_root_oclass,
.uevent = &gf119_disp_chan_uevent,
.head = { .cnt = gf119_head_cnt, .new = gf119_head_new },
.sor = { .cnt = gf119_sor_cnt, .new = gp100_sor_new },
.root = { 0,0,GP102_DISP },
.user = {
{{0,0,GK104_DISP_CURSOR }, nvkm_disp_chan_new, &gp102_disp_curs },
{{0,0,GK104_DISP_OVERLAY }, nvkm_disp_chan_new, &gp102_disp_oimm },
{{0,0,GK110_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, &gp102_disp_base },
{{0,0,GP102_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, &gp102_disp_core },
{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gp102_disp_ovly },
{}
},
};
int
gp102_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gp102_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gp102_disp, device, type, inst, pdisp);
}

View file

@ -21,28 +21,89 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
#include <nvif/class.h>
static const struct nvkm_disp_mthd_list
gt200_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 },
{ 0x00b0, 0x610c98 },
{ 0x00b4, 0x610ca4 },
{ 0x00b8, 0x610cac },
{ 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
gt200_disp_ovly_mthd = {
.name = "Overlay",
.addr = 0x000540,
.prev = 0x000004,
.data = {
{ "Global", 1, &gt200_disp_ovly_mthd_base },
{}
}
};
const struct nvkm_disp_chan_user
gt200_disp_ovly = {
.func = &nv50_disp_dmac_func,
.ctrl = 3,
.user = 3,
.mthd = &gt200_disp_ovly_mthd,
};
static const struct nvkm_disp_func
gt200_disp = {
.oneinit = nv50_disp_oneinit,
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super,
.root = &gt200_disp_root_oclass,
.uevent = &nv50_disp_chan_uevent,
.head = { .cnt = nv50_head_cnt, .new = nv50_head_new },
.dac = { .cnt = nv50_dac_cnt, .new = nv50_dac_new },
.sor = { .cnt = nv50_sor_cnt, .new = g84_sor_new },
.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
.root = { 0,0,GT200_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,GT200_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, & g84_disp_base },
{{0,0,GT200_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, & g84_disp_core },
{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, &gt200_disp_ovly },
{}
},
};
int
gt200_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gt200_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gt200_disp, device, type, inst, pdisp);
}

View file

@ -21,28 +21,188 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "priv.h"
#include "chan.h"
#include "hdmi.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
#include <subdev/timer.h>
#include <nvif/class.h>
static void
gt215_sor_hda_eld(struct nvkm_ior *ior, int head, u8 *data, u8 size)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = ior->id * 0x800;
int i;
for (i = 0; i < size; i++)
nvkm_wr32(device, 0x61c440 + soff, (i << 8) | data[i]);
for (; i < 0x60; i++)
nvkm_wr32(device, 0x61c440 + soff, (i << 8));
nvkm_mask(device, 0x61c448 + soff, 0x80000002, 0x80000002);
}
static void
gt215_sor_hda_hpd(struct nvkm_ior *ior, int head, bool present)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
u32 data = 0x80000000;
u32 mask = 0x80000001;
if (present)
data |= 0x00000001;
else
mask |= 0x00000002;
nvkm_mask(device, 0x61c448 + ior->id * 0x800, mask, data);
}
const struct nvkm_ior_func_hda
gt215_sor_hda = {
.hpd = gt215_sor_hda_hpd,
.eld = gt215_sor_hda_eld,
};
void
gt215_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable)
{
struct nvkm_device *device = sor->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(sor);
const u32 data = 0x80000000 | (0x00000001 * enable);
const u32 mask = 0x8000000d;
nvkm_mask(device, 0x61c1e0 + soff, mask, data);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61c1e0 + soff) & 0x80000000))
break;
);
}
static const struct nvkm_ior_func_dp
gt215_sor_dp = {
.lanes = { 2, 1, 0, 3 },
.links = g94_sor_dp_links,
.power = g94_sor_dp_power,
.pattern = g94_sor_dp_pattern,
.drive = g94_sor_dp_drive,
.audio = gt215_sor_dp_audio,
.audio_sym = g94_sor_dp_audio_sym,
.activesym = g94_sor_dp_activesym,
.watermark = g94_sor_dp_watermark,
};
void
gt215_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 soff = nv50_ior_base(ior);
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, 0x61c5a4 + soff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x61c53c + soff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x61c528 + soff, avi_infoframe.header);
nvkm_wr32(device, 0x61c52c + soff, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x61c530 + soff, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x61c534 + soff, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x61c538 + soff, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001);
}
/* Audio InfoFrame */
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x61c508 + soff, 0x000a0184);
nvkm_wr32(device, 0x61c50c + soff, 0x00000071);
nvkm_wr32(device, 0x61c510 + soff, 0x00000000);
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001);
/* Vendor InfoFrame */
nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000);
if (vendor_size) {
nvkm_wr32(device, 0x61c544 + soff, vendor_infoframe.header);
nvkm_wr32(device, 0x61c548 + soff, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x61c54c + soff, vendor_infoframe.subpack0_high);
/* Is there a second (or up to fourth?) set of subpack registers here? */
/* nvkm_wr32(device, 0x61c550 + soff, vendor_infoframe.subpack1_low); */
/* nvkm_wr32(device, 0x61c554 + soff, vendor_infoframe.subpack1_high); */
nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001);
}
nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
nvkm_mask(device, 0x61c578 + soff, 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, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
}
static const struct nvkm_ior_func
gt215_sor = {
.state = g94_sor_state,
.power = nv50_sor_power,
.clock = nv50_sor_clock,
.hdmi = {
.ctrl = gt215_sor_hdmi_ctrl,
},
.dp = &gt215_sor_dp,
.hda = &gt215_sor_hda,
};
static int
gt215_sor_new(struct nvkm_disp *disp, int id)
{
return nvkm_ior_new_(&gt215_sor, disp, SOR, id, true);
}
static const struct nvkm_disp_func
gt215_disp = {
.oneinit = nv50_disp_oneinit,
.init = nv50_disp_init,
.fini = nv50_disp_fini,
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_super,
.root = &gt215_disp_root_oclass,
.uevent = &nv50_disp_chan_uevent,
.head = { .cnt = nv50_head_cnt, .new = nv50_head_new },
.dac = { .cnt = nv50_dac_cnt, .new = nv50_dac_new },
.sor = { .cnt = g94_sor_cnt, .new = gt215_sor_new },
.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
.root = { 0,0,GT214_DISP },
.user = {
{{0,0,GT214_DISP_CURSOR }, nvkm_disp_chan_new, & nv50_disp_curs },
{{0,0,GT214_DISP_OVERLAY }, nvkm_disp_chan_new, & nv50_disp_oimm },
{{0,0,GT214_DISP_BASE_CHANNEL_DMA }, nvkm_disp_chan_new, & g84_disp_base },
{{0,0,GT214_DISP_CORE_CHANNEL_DMA }, nvkm_disp_core_new, & g94_disp_core },
{{0,0,GT214_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, & g84_disp_ovly },
{}
},
};
int
gt215_disp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
struct nvkm_disp **pdisp)
{
return nv50_disp_new_(&gt215_disp, device, type, inst, pdisp);
return nvkm_disp_new_(&gt215_disp, device, type, inst, pdisp);
}

File diff suppressed because it is too large Load diff

View file

@ -1,62 +0,0 @@
/*
* 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"
void
gf119_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, 0x616548 + hoff, 0x00000070, head << 4);
}
void
gf119_hda_eld(struct nvkm_ior *ior, int head, u8 *data, u8 size)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = 0x030 * ior->id + (head * 0x04);
int i;
for (i = 0; i < size; i++)
nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | data[i]);
for (; i < 0x60; i++)
nvkm_wr32(device, 0x10ec00 + soff, (i << 8));
nvkm_mask(device, 0x10ec10 + soff, 0x80000002, 0x80000002);
}
void
gf119_hda_hpd(struct nvkm_ior *ior, int head, bool present)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = 0x030 * ior->id + (head * 0x04);
u32 data = 0x80000000;
u32 mask = 0x80000001;
if (present) {
ior->func->hda.device_entry(ior, head);
data |= 0x00000001;
} else {
mask |= 0x00000002;
}
nvkm_mask(device, 0x10ec10 + soff, mask, data);
}

View file

@ -1,51 +0,0 @@
/*
* 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"
void
gt215_hda_eld(struct nvkm_ior *ior, int head, u8 *data, u8 size)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = ior->id * 0x800;
int i;
for (i = 0; i < size; i++)
nvkm_wr32(device, 0x61c440 + soff, (i << 8) | data[i]);
for (; i < 0x60; i++)
nvkm_wr32(device, 0x61c440 + soff, (i << 8));
nvkm_mask(device, 0x61c448 + soff, 0x80000002, 0x80000002);
}
void
gt215_hda_hpd(struct nvkm_ior *ior, int head, bool present)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
u32 data = 0x80000000;
u32 mask = 0x80000001;
if (present)
data |= 0x00000001;
else
mask |= 0x00000002;
nvkm_mask(device, 0x61c448 + ior->id * 0x800, mask, data);
}

View file

@ -1,30 +0,0 @@
/*
* 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);
}

View file

@ -1,91 +0,0 @@
/*
* 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 "hdmi.h"
void
g84_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);
}

View file

@ -1,82 +0,0 @@
/*
* 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 "hdmi.h"
void
gf119_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 |
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, 0x616798 + hoff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x61671c + hoff, avi_infoframe.header);
nvkm_wr32(device, 0x616720 + hoff, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x616724 + hoff, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x616728 + hoff, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x61672c + hoff, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001);
}
/* GENERIC(?) / Vendor InfoFrame? */
nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000);
if (vendor_size) {
/*
* These appear to be the audio infoframe registers,
* but no other set of infoframe registers has yet
* been found.
*/
nvkm_wr32(device, 0x616738 + hoff, vendor_infoframe.header);
nvkm_wr32(device, 0x61673c + hoff, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x616740 + hoff, vendor_infoframe.subpack0_high);
/* Is there a second (or further?) set of subpack registers here? */
nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000001);
}
/* ??? InfoFrame? */
nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x6167ac + hoff, 0x00000010);
nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000001);
/* HDMI_CTRL */
nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl);
}

View file

@ -1,82 +0,0 @@
/*
* Copyright 2014 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 "hdmi.h"
void
gk104_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 |
max_ac_packet << 16 |
rekey;
const u32 hoff = head * 0x800;
const u32 hdmi = head * 0x400;
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, 0x616798 + hoff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000000);
nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x690008 + hdmi, avi_infoframe.header);
nvkm_wr32(device, 0x69000c + hdmi, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x690010 + hdmi, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x690014 + hdmi, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x690018 + hdmi, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001);
}
/* GENERIC(?) / Vendor InfoFrame? */
nvkm_mask(device, 0x690100 + hdmi, 0x00010001, 0x00000000);
if (vendor_size) {
nvkm_wr32(device, 0x690108 + hdmi, vendor_infoframe.header);
nvkm_wr32(device, 0x69010c + hdmi, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x690110 + hdmi, vendor_infoframe.subpack0_high);
/* Is there a second (or further?) set of subpack registers here? */
nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000001);
}
/* ??? InfoFrame? */
nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x6900cc + hdmi, 0x00000010);
nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
/* ??? */
nvkm_wr32(device, 0x690080 + hdmi, 0x82000000);
/* HDMI_CTRL */
nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl);
}

View file

@ -1,36 +0,0 @@
/*
* Copyright 2018 Ilia Mirkin
*
* 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: Ilia Mirkin
*/
#include "hdmi.h"
void
gm200_hdmi_scdc(struct nvkm_ior *ior, u8 scdc)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = nv50_ior_base(ior);
const u32 ctrl = scdc & 0x3;
nvkm_mask(device, 0x61c5bc + soff, 0x00000003, ctrl);
ior->tmds.high_speed = !!(scdc & 0x2);
}

View file

@ -1,91 +0,0 @@
/*
* 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 "hdmi.h"
void
gt215_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 soff = nv50_ior_base(ior);
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, 0x61c5a4 + soff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x61c53c + soff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x61c528 + soff, avi_infoframe.header);
nvkm_wr32(device, 0x61c52c + soff, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x61c530 + soff, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x61c534 + soff, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x61c538 + soff, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001);
}
/* Audio InfoFrame */
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x61c508 + soff, 0x000a0184);
nvkm_wr32(device, 0x61c50c + soff, 0x00000071);
nvkm_wr32(device, 0x61c510 + soff, 0x00000000);
nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001);
/* Vendor InfoFrame */
nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000);
if (vendor_size) {
nvkm_wr32(device, 0x61c544 + soff, vendor_infoframe.header);
nvkm_wr32(device, 0x61c548 + soff, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x61c54c + soff, vendor_infoframe.subpack0_high);
/* Is there a second (or up to fourth?) set of subpack registers here? */
/* nvkm_wr32(device, 0x61c550 + soff, vendor_infoframe.subpack1_low); */
/* nvkm_wr32(device, 0x61c554 + soff, vendor_infoframe.subpack1_high); */
nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001);
}
nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
nvkm_mask(device, 0x61c578 + soff, 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, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
}

View file

@ -1,84 +0,0 @@
/*
* 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 "hdmi.h"
void
gv100_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 |
max_ac_packet << 16 |
rekey;
const u32 hoff = head * 0x800;
const u32 hdmi = head * 0x400;
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, 0x6165c0 + hoff, 0x40000000, 0x00000000);
nvkm_mask(device, 0x6f0100 + hdmi, 0x00000001, 0x00000000);
nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000000);
nvkm_mask(device, 0x6f0000 + hdmi, 0x00000001, 0x00000000);
return;
}
/* AVI InfoFrame (AVI). */
nvkm_mask(device, 0x6f0000 + hdmi, 0x00000001, 0x00000000);
if (avi_size) {
nvkm_wr32(device, 0x6f0008 + hdmi, avi_infoframe.header);
nvkm_wr32(device, 0x6f000c + hdmi, avi_infoframe.subpack0_low);
nvkm_wr32(device, 0x6f0010 + hdmi, avi_infoframe.subpack0_high);
nvkm_wr32(device, 0x6f0014 + hdmi, avi_infoframe.subpack1_low);
nvkm_wr32(device, 0x6f0018 + hdmi, avi_infoframe.subpack1_high);
nvkm_mask(device, 0x6f0000 + hdmi, 0x00000001, 0x00000001);
}
/* Vendor-specific InfoFrame (VSI). */
nvkm_mask(device, 0x6f0100 + hdmi, 0x00010001, 0x00000000);
if (vendor_size) {
nvkm_wr32(device, 0x6f0108 + hdmi, vendor_infoframe.header);
nvkm_wr32(device, 0x6f010c + hdmi, vendor_infoframe.subpack0_low);
nvkm_wr32(device, 0x6f0110 + hdmi, vendor_infoframe.subpack0_high);
nvkm_wr32(device, 0x6f0114 + hdmi, 0x00000000);
nvkm_wr32(device, 0x6f0118 + hdmi, 0x00000000);
nvkm_wr32(device, 0x6f011c + hdmi, 0x00000000);
nvkm_wr32(device, 0x6f0120 + hdmi, 0x00000000);
nvkm_wr32(device, 0x6f0124 + hdmi, 0x00000000);
nvkm_mask(device, 0x6f0100 + hdmi, 0x00000001, 0x00000001);
}
/* General Control (GCP). */
nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x6f00cc + hdmi, 0x00000010);
nvkm_mask(device, 0x6f00c0 + hdmi, 0x00000001, 0x00000001);
/* Audio Clock Regeneration (ACR). */
nvkm_wr32(device, 0x6f0080 + hdmi, 0x82000000);
/* NV_PDISP_SF_HDMI_CTRL. */
nvkm_mask(device, 0x6165c0 + hoff, 0x401f007f, ctrl);
}

View file

@ -32,7 +32,7 @@ struct nvkm_head *
nvkm_head_find(struct nvkm_disp *disp, int id)
{
struct nvkm_head *head;
list_for_each_entry(head, &disp->head, head) {
list_for_each_entry(head, &disp->heads, head) {
if (head->id == id)
return head;
}
@ -99,7 +99,7 @@ nvkm_head_new_(const struct nvkm_head_func *func,
head->func = func;
head->disp = disp;
head->id = id;
list_add_tail(&head->head, &disp->head);
list_add_tail(&head->head, &disp->heads);
HEAD_DBG(head, "ctor");
return 0;
}

View file

@ -42,19 +42,9 @@ struct nvkm_head_func {
void (*vblank_put)(struct nvkm_head *);
};
void nv50_head_rgpos(struct nvkm_head *, u16 *, u16 *);
#define HEAD_MSG(h,l,f,a...) do { \
struct nvkm_head *_h = (h); \
nvkm_##l(&_h->disp->engine.subdev, "head-%d: "f"\n", _h->id, ##a); \
} while(0)
#define HEAD_WARN(h,f,a...) HEAD_MSG((h), warn, f, ##a)
#define HEAD_DBG(h,f,a...) HEAD_MSG((h), debug, f, ##a)
int nv04_head_new(struct nvkm_disp *, int id);
int nv50_head_cnt(struct nvkm_disp *, unsigned long *);
int nv50_head_new(struct nvkm_disp *, int id);
void nv50_head_rgpos(struct nvkm_head *, u16 *, u16 *);
int gf119_head_cnt(struct nvkm_disp *, unsigned long *);
int gf119_head_new(struct nvkm_disp *, int id);
@ -62,4 +52,11 @@ void gf119_head_rgclk(struct nvkm_head *, int);
int gv100_head_cnt(struct nvkm_disp *, unsigned long *);
int gv100_head_new(struct nvkm_disp *, int id);
#define HEAD_MSG(h,l,f,a...) do { \
struct nvkm_head *_h = (h); \
nvkm_##l(&_h->disp->engine.subdev, "head-%d: "f"\n", _h->id, ##a); \
} while(0)
#define HEAD_WARN(h,f,a...) HEAD_MSG((h), warn, f, ##a)
#define HEAD_DBG(h,f,a...) HEAD_MSG((h), debug, f, ##a)
#endif

View file

@ -1,104 +0,0 @@
/*
* 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.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "head.h"
static void
gf119_head_vblank_put(struct nvkm_head *head)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
const u32 hoff = head->id * 0x800;
nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000000);
}
static void
gf119_head_vblank_get(struct nvkm_head *head)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
const u32 hoff = head->id * 0x800;
nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000001);
}
void
gf119_head_rgclk(struct nvkm_head *head, int div)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
nvkm_mask(device, 0x612200 + (head->id * 0x800), 0x0000000f, div);
}
static void
gf119_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
const u32 hoff = (state == &head->asy) * 0x20000 + head->id * 0x300;
u32 data;
data = nvkm_rd32(device, 0x640414 + hoff);
state->vtotal = (data & 0xffff0000) >> 16;
state->htotal = (data & 0x0000ffff);
data = nvkm_rd32(device, 0x640418 + hoff);
state->vsynce = (data & 0xffff0000) >> 16;
state->hsynce = (data & 0x0000ffff);
data = nvkm_rd32(device, 0x64041c + hoff);
state->vblanke = (data & 0xffff0000) >> 16;
state->hblanke = (data & 0x0000ffff);
data = nvkm_rd32(device, 0x640420 + hoff);
state->vblanks = (data & 0xffff0000) >> 16;
state->hblanks = (data & 0x0000ffff);
state->hz = nvkm_rd32(device, 0x640450 + hoff);
data = nvkm_rd32(device, 0x640404 + hoff);
switch ((data & 0x000003c0) >> 6) {
case 6: state->or.depth = 30; break;
case 5: state->or.depth = 24; break;
case 2: state->or.depth = 18; break;
case 0: state->or.depth = 18; break; /*XXX: "default" */
default:
state->or.depth = 18;
WARN_ON(1);
break;
}
}
static const struct nvkm_head_func
gf119_head = {
.state = gf119_head_state,
.rgpos = nv50_head_rgpos,
.rgclk = gf119_head_rgclk,
.vblank_get = gf119_head_vblank_get,
.vblank_put = gf119_head_vblank_put,
};
int
gf119_head_new(struct nvkm_disp *disp, int id)
{
return nvkm_head_new_(&gf119_head, disp, id);
}
int
gf119_head_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = nvkm_rd32(device, 0x612004) & 0x0000000f;
return nvkm_rd32(device, 0x022448);
}

View file

@ -1,105 +0,0 @@
/*
* 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 "head.h"
static void
gv100_head_vblank_put(struct nvkm_head *head)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000004, 0x00000000);
}
static void
gv100_head_vblank_get(struct nvkm_head *head)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
nvkm_mask(device, 0x611d80 + (head->id * 4), 0x00000004, 0x00000004);
}
static void
gv100_head_rgpos(struct nvkm_head *head, u16 *hline, u16 *vline)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
const u32 hoff = head->id * 0x800;
/* vline read locks hline. */
*vline = nvkm_rd32(device, 0x616330 + hoff) & 0x0000ffff;
*hline = nvkm_rd32(device, 0x616334 + hoff) & 0x0000ffff;
}
static void
gv100_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
const u32 hoff = (state == &head->arm) * 0x8000 + head->id * 0x400;
u32 data;
data = nvkm_rd32(device, 0x682064 + hoff);
state->vtotal = (data & 0xffff0000) >> 16;
state->htotal = (data & 0x0000ffff);
data = nvkm_rd32(device, 0x682068 + hoff);
state->vsynce = (data & 0xffff0000) >> 16;
state->hsynce = (data & 0x0000ffff);
data = nvkm_rd32(device, 0x68206c + hoff);
state->vblanke = (data & 0xffff0000) >> 16;
state->hblanke = (data & 0x0000ffff);
data = nvkm_rd32(device, 0x682070 + hoff);
state->vblanks = (data & 0xffff0000) >> 16;
state->hblanks = (data & 0x0000ffff);
state->hz = nvkm_rd32(device, 0x68200c + hoff);
data = nvkm_rd32(device, 0x682004 + hoff);
switch ((data & 0x000000f0) >> 4) {
case 5: state->or.depth = 30; break;
case 4: state->or.depth = 24; break;
case 1: state->or.depth = 18; break;
default:
state->or.depth = 18;
WARN_ON(1);
break;
}
}
static const struct nvkm_head_func
gv100_head = {
.state = gv100_head_state,
.rgpos = gv100_head_rgpos,
.rgclk = gf119_head_rgclk,
.vblank_get = gv100_head_vblank_get,
.vblank_put = gv100_head_vblank_put,
};
int
gv100_head_new(struct nvkm_disp *disp, int id)
{
struct nvkm_device *device = disp->engine.subdev.device;
if (!(nvkm_rd32(device, 0x610060) & (0x00000001 << id)))
return 0;
return nvkm_head_new_(&gv100_head, disp, id);
}
int
gv100_head_cnt(struct nvkm_disp *disp, unsigned long *pmask)
{
struct nvkm_device *device = disp->engine.subdev.device;
*pmask = nvkm_rd32(device, 0x610060) & 0x000000ff;
return nvkm_rd32(device, 0x610074) & 0x0000000f;
}

View file

@ -1,74 +0,0 @@
/*
* 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.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "head.h"
static void
nv04_head_vblank_put(struct nvkm_head *head)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
nvkm_wr32(device, 0x600140 + (head->id * 0x2000) , 0x00000000);
}
static void
nv04_head_vblank_get(struct nvkm_head *head)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
nvkm_wr32(device, 0x600140 + (head->id * 0x2000) , 0x00000001);
}
static void
nv04_head_rgpos(struct nvkm_head *head, u16 *hline, u16 *vline)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
u32 data = nvkm_rd32(device, 0x600868 + (head->id * 0x2000));
*hline = (data & 0xffff0000) >> 16;
*vline = (data & 0x0000ffff);
}
static void
nv04_head_state(struct nvkm_head *head, struct nvkm_head_state *state)
{
struct nvkm_device *device = head->disp->engine.subdev.device;
const u32 hoff = head->id * 0x0200;
state->vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0x0000ffff;
state->vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0x0000ffff;
state->vblanke = state->vtotal - 1;
state->hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0x0000ffff;
state->htotal = nvkm_rd32(device, 0x680824 + hoff) & 0x0000ffff;
state->hblanke = state->htotal - 1;
}
static const struct nvkm_head_func
nv04_head = {
.state = nv04_head_state,
.rgpos = nv04_head_rgpos,
.vblank_get = nv04_head_vblank_get,
.vblank_put = nv04_head_vblank_put,
};
int
nv04_head_new(struct nvkm_disp *disp, int id)
{
return nvkm_head_new_(&nv04_head, disp, id);
}

Some files were not shown because too many files have changed in this diff Show more