提交 bf0eb898 编写于 作者: B Ben Skeggs

drm/nv50-/disp: audit and version DAC_PWR method

The full object interfaces are about to be exposed to userspace, so we
need to check for any security-related issues and version the structs
to make it easier to handle any changes we may need in the future.
Signed-off-by: NBen Skeggs <bskeggs@redhat.com>
上级 2c04ae01
...@@ -22,8 +22,10 @@ ...@@ -22,8 +22,10 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <core/os.h> #include <core/client.h>
#include <core/class.h> #include <core/class.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
...@@ -32,13 +34,28 @@ ...@@ -32,13 +34,28 @@
#include "nv50.h" #include "nv50.h"
int int
nv50_dac_power(struct nv50_disp_priv *priv, int or, u32 data) nv50_dac_power(NV50_DISP_MTHD_V1)
{ {
const u32 stat = (data & NV50_DISP_DAC_PWR_HSYNC) | const u32 doff = outp->or * 0x800;
(data & NV50_DISP_DAC_PWR_VSYNC) | union {
(data & NV50_DISP_DAC_PWR_DATA) | struct nv50_disp_dac_pwr_v0 v0;
(data & NV50_DISP_DAC_PWR_STATE); } *args = data;
const u32 doff = (or * 0x800); u32 stat;
int ret;
nv_ioctl(object, "disp dac pwr size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp dac pwr vers %d state %d data %d "
"vsync %d hsync %d\n",
args->v0.version, args->v0.state, args->v0.data,
args->v0.vsync, args->v0.hsync);
stat = 0x00000040 * !args->v0.state;
stat |= 0x00000010 * !args->v0.data;
stat |= 0x00000004 * !args->v0.vsync;
stat |= 0x00000001 * !args->v0.hsync;
} else
return ret;
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
...@@ -80,9 +97,6 @@ nv50_dac_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) ...@@ -80,9 +97,6 @@ nv50_dac_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
return -EINVAL; return -EINVAL;
switch (mthd & ~0x3f) { switch (mthd & ~0x3f) {
case NV50_DISP_DAC_PWR:
ret = priv->dac.power(priv, or, data[0]);
break;
case NV50_DISP_DAC_LOAD: case NV50_DISP_DAC_LOAD:
ret = priv->dac.sense(priv, or, data[0]); ret = priv->dac.sense(priv, or, data[0]);
if (ret >= 0) { if (ret >= 0) {
......
...@@ -23,10 +23,13 @@ ...@@ -23,10 +23,13 @@
*/ */
#include <core/object.h> #include <core/object.h>
#include <core/client.h>
#include <core/parent.h> #include <core/parent.h>
#include <core/handle.h> #include <core/handle.h>
#include <core/class.h>
#include <core/enum.h> #include <core/enum.h>
#include <core/class.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
...@@ -839,6 +842,72 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, ...@@ -839,6 +842,72 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
return 0; return 0;
} }
int
nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
void *data, u32 size)
{
union {
struct nv50_disp_mthd_v0 v0;
struct nv50_disp_mthd_v1 v1;
} *args = data;
struct nv50_disp_priv *priv = (void *)object->engine;
struct nvkm_output *outp = NULL;
struct nvkm_output *temp;
u16 type, mask = 0;
int head, ret;
if (mthd != NV50_DISP_MTHD)
return -EINVAL;
nv_ioctl(object, "disp mthd size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, true)) {
nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
args->v0.version, args->v0.method, args->v0.head);
mthd = args->v0.method;
head = args->v0.head;
} else
if (nvif_unpack(args->v1, 1, 1, true)) {
nv_ioctl(object, "disp mthd vers %d mthd %02x "
"type %04x mask %04x\n",
args->v1.version, args->v1.method,
args->v1.hasht, args->v1.hashm);
mthd = args->v1.method;
type = args->v1.hasht;
mask = args->v1.hashm;
head = ffs((mask >> 8) & 0x0f) - 1;
} else
return ret;
if (head < 0 || head >= priv->head.nr)
return -ENXIO;
if (mask) {
list_for_each_entry(temp, &priv->base.outp, head) {
if ((temp->info.hasht == type) &&
(temp->info.hashm & mask) == mask) {
outp = temp;
break;
}
}
if (outp == NULL)
return -ENXIO;
}
switch (mthd) {
default:
break;
}
switch (mthd * !!outp) {
case NV50_DISP_MTHD_V1_DAC_PWR:
return priv->dac.power(object, priv, data, size, head, outp);
default:
break;
}
return -EINVAL;
}
int int
nv50_disp_base_ctor(struct nouveau_object *parent, nv50_disp_base_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
...@@ -954,6 +1023,7 @@ nv50_disp_base_ofuncs = { ...@@ -954,6 +1023,7 @@ nv50_disp_base_ofuncs = {
.dtor = nv50_disp_base_dtor, .dtor = nv50_disp_base_dtor,
.init = nv50_disp_base_init, .init = nv50_disp_base_init,
.fini = nv50_disp_base_fini, .fini = nv50_disp_base_fini,
.mthd = nv50_disp_base_mthd,
}; };
static struct nouveau_omthds static struct nouveau_omthds
...@@ -961,7 +1031,6 @@ nv50_disp_base_omthds[] = { ...@@ -961,7 +1031,6 @@ nv50_disp_base_omthds[] = {
{ HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos }, { HEAD_MTHD(NV50_DISP_SCANOUTPOS) , nv50_disp_base_scanoutpos },
{ SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
......
...@@ -24,6 +24,11 @@ struct nv50_disp_impl { ...@@ -24,6 +24,11 @@ struct nv50_disp_impl {
} mthd; } mthd;
}; };
#define NV50_DISP_MTHD_ struct nouveau_object *object, \
struct nv50_disp_priv *priv, void *data, u32 size
#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp
struct nv50_disp_priv { struct nv50_disp_priv {
struct nouveau_disp base; struct nouveau_disp base;
struct nouveau_oclass *sclass; struct nouveau_oclass *sclass;
...@@ -36,7 +41,7 @@ struct nv50_disp_priv { ...@@ -36,7 +41,7 @@ struct nv50_disp_priv {
} head; } head;
struct { struct {
int nr; int nr;
int (*power)(struct nv50_disp_priv *, int dac, u32 data); int (*power)(NV50_DISP_MTHD_V1);
int (*sense)(struct nv50_disp_priv *, int dac, u32 load); int (*sense)(struct nv50_disp_priv *, int dac, u32 load);
} dac; } dac;
struct { struct {
...@@ -56,11 +61,12 @@ struct nv50_disp_priv { ...@@ -56,11 +61,12 @@ struct nv50_disp_priv {
#define HEAD_MTHD(n) (n), (n) + 0x03 #define HEAD_MTHD(n) (n), (n) + 0x03
int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32); int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32);
int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32);
#define DAC_MTHD(n) (n), (n) + 0x03 #define DAC_MTHD(n) (n), (n) + 0x03
int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32); int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32);
int nv50_dac_power(struct nv50_disp_priv *, int, u32); int nv50_dac_power(NV50_DISP_MTHD_V1);
int nv50_dac_sense(struct nv50_disp_priv *, int, u32); int nv50_dac_sense(struct nv50_disp_priv *, int, u32);
#define SOR_MTHD(n) (n), (n) + 0x3f #define SOR_MTHD(n) (n), (n) + 0x3f
......
...@@ -218,7 +218,6 @@ nv84_disp_base_omthds[] = { ...@@ -218,7 +218,6 @@ nv84_disp_base_omthds[] = {
{ SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
......
...@@ -78,7 +78,6 @@ nv94_disp_base_omthds[] = { ...@@ -78,7 +78,6 @@ nv94_disp_base_omthds[] = {
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
......
...@@ -51,7 +51,6 @@ nva3_disp_base_omthds[] = { ...@@ -51,7 +51,6 @@ nva3_disp_base_omthds[] = {
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
......
...@@ -706,6 +706,7 @@ nvd0_disp_base_ofuncs = { ...@@ -706,6 +706,7 @@ nvd0_disp_base_ofuncs = {
.dtor = nv50_disp_base_dtor, .dtor = nv50_disp_base_dtor,
.init = nvd0_disp_base_init, .init = nvd0_disp_base_init,
.fini = nvd0_disp_base_fini, .fini = nvd0_disp_base_fini,
.mthd = nv50_disp_base_mthd,
}; };
struct nouveau_omthds struct nouveau_omthds
...@@ -716,7 +717,6 @@ nvd0_disp_base_omthds[] = { ...@@ -716,7 +717,6 @@ nvd0_disp_base_omthds[] = {
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR) , nv50_pior_mthd },
......
...@@ -78,6 +78,7 @@ nvkm_output_create_(struct nouveau_object *parent, ...@@ -78,6 +78,7 @@ nvkm_output_create_(struct nouveau_object *parent,
outp->info = *dcbE; outp->info = *dcbE;
outp->index = index; outp->index = index;
outp->or = ffs(outp->info.or) - 1;
DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n", DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ? dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
......
...@@ -9,6 +9,7 @@ struct nvkm_output { ...@@ -9,6 +9,7 @@ struct nvkm_output {
struct dcb_output info; struct dcb_output info;
int index; int index;
int or;
struct nouveau_i2c_port *port; struct nouveau_i2c_port *port;
struct nouveau_i2c_port *edid; struct nouveau_i2c_port *edid;
......
...@@ -49,7 +49,6 @@ struct nv04_display_scanoutpos { ...@@ -49,7 +49,6 @@ struct nv04_display_scanoutpos {
#define NVF0_DISP_CLASS 0x00009270 #define NVF0_DISP_CLASS 0x00009270
#define GM107_DISP_CLASS 0x00009470 #define GM107_DISP_CLASS 0x00009470
#define NV50_DISP_MTHD 0x00000000
#define NV50_DISP_MTHD_HEAD 0x00000003 #define NV50_DISP_MTHD_HEAD 0x00000003
#define NV50_DISP_SCANOUTPOS 0x00000000 #define NV50_DISP_SCANOUTPOS 0x00000000
...@@ -82,19 +81,6 @@ struct nv04_display_scanoutpos { ...@@ -82,19 +81,6 @@ struct nv04_display_scanoutpos {
#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000 #define NV50_DISP_DAC_MTHD_TYPE 0x0000f000
#define NV50_DISP_DAC_MTHD_OR 0x00000003 #define NV50_DISP_DAC_MTHD_OR 0x00000003
#define NV50_DISP_DAC_PWR 0x00020000
#define NV50_DISP_DAC_PWR_HSYNC 0x00000001
#define NV50_DISP_DAC_PWR_HSYNC_ON 0x00000000
#define NV50_DISP_DAC_PWR_HSYNC_LO 0x00000001
#define NV50_DISP_DAC_PWR_VSYNC 0x00000004
#define NV50_DISP_DAC_PWR_VSYNC_ON 0x00000000
#define NV50_DISP_DAC_PWR_VSYNC_LO 0x00000004
#define NV50_DISP_DAC_PWR_DATA 0x00000010
#define NV50_DISP_DAC_PWR_DATA_ON 0x00000000
#define NV50_DISP_DAC_PWR_DATA_LO 0x00000010
#define NV50_DISP_DAC_PWR_STATE 0x00000040
#define NV50_DISP_DAC_PWR_STATE_ON 0x00000000
#define NV50_DISP_DAC_PWR_STATE_OFF 0x00000040
#define NV50_DISP_DAC_LOAD 0x00020100 #define NV50_DISP_DAC_LOAD 0x00020100
#define NV50_DISP_DAC_LOAD_VALUE 0x00000007 #define NV50_DISP_DAC_LOAD_VALUE 0x00000007
......
...@@ -1397,6 +1397,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, ...@@ -1397,6 +1397,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
uint32_t conn, uint32_t conf, struct dcb_output *entry) uint32_t conn, uint32_t conf, struct dcb_output *entry)
{ {
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
int link = 0;
entry->type = conn & 0xf; entry->type = conn & 0xf;
entry->i2c_index = (conn >> 4) & 0xf; entry->i2c_index = (conn >> 4) & 0xf;
...@@ -1442,6 +1443,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, ...@@ -1442,6 +1443,7 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
if (conf & 0x4) if (conf & 0x4)
entry->lvdsconf.use_power_scripts = true; entry->lvdsconf.use_power_scripts = true;
entry->lvdsconf.sor.link = (conf & 0x00000030) >> 4; entry->lvdsconf.sor.link = (conf & 0x00000030) >> 4;
link = entry->lvdsconf.sor.link;
} }
if (conf & mask) { if (conf & mask) {
/* /*
...@@ -1490,17 +1492,18 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, ...@@ -1490,17 +1492,18 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
entry->dpconf.link_nr = 1; entry->dpconf.link_nr = 1;
break; break;
} }
link = entry->dpconf.sor.link;
break; break;
case DCB_OUTPUT_TMDS: case DCB_OUTPUT_TMDS:
if (dcb->version >= 0x40) { if (dcb->version >= 0x40) {
entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
entry->extdev = (conf & 0x0000ff00) >> 8; entry->extdev = (conf & 0x0000ff00) >> 8;
link = entry->tmdsconf.sor.link;
} }
else if (dcb->version >= 0x30) else if (dcb->version >= 0x30)
entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8; entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
else if (dcb->version >= 0x22) else if (dcb->version >= 0x22)
entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4; entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
break; break;
case DCB_OUTPUT_EOL: case DCB_OUTPUT_EOL:
/* weird g80 mobile type that "nv" treats as a terminator */ /* weird g80 mobile type that "nv" treats as a terminator */
...@@ -1524,6 +1527,8 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, ...@@ -1524,6 +1527,8 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
if (conf & 0x100000) if (conf & 0x100000)
entry->i2c_upper_default = true; entry->i2c_upper_default = true;
entry->hasht = (entry->location << 4) | entry->type;
entry->hashm = (entry->heads << 8) | (link << 6) | entry->or;
return true; return true;
} }
......
...@@ -1466,16 +1466,24 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode) ...@@ -1466,16 +1466,24 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
{ {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_disp *disp = nv50_disp(encoder->dev); struct nv50_disp *disp = nv50_disp(encoder->dev);
int or = nv_encoder->or; struct {
u32 dpms_ctrl; struct nv50_disp_mthd_v1 base;
struct nv50_disp_dac_pwr_v0 pwr;
} args = {
.base.version = 1,
.base.method = NV50_DISP_MTHD_V1_DAC_PWR,
.base.hasht = nv_encoder->dcb->hasht,
.base.hashm = nv_encoder->dcb->hashm,
.pwr.state = 1,
.pwr.data = 1,
.pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND &&
mode != DRM_MODE_DPMS_OFF),
.pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY &&
mode != DRM_MODE_DPMS_OFF),
};
dpms_ctrl = 0x00000000;
if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF)
dpms_ctrl |= 0x00000001;
if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF)
dpms_ctrl |= 0x00000004;
nvif_exec(disp->disp, NV50_DISP_DAC_PWR + or, &dpms_ctrl, sizeof(dpms_ctrl)); nvif_mthd(disp->disp, 0, &args, sizeof(args));
} }
static bool static bool
......
...@@ -290,4 +290,47 @@ struct kepler_channel_gpfifo_a_v0 { ...@@ -290,4 +290,47 @@ struct kepler_channel_gpfifo_a_v0 {
__u64 ioffset; __u64 ioffset;
}; };
/*******************************************************************************
* legacy display
******************************************************************************/
/*******************************************************************************
* display
******************************************************************************/
#define NV50_DISP_MTHD 0x00
struct nv50_disp_mthd_v0 {
__u8 version;
__u8 method;
__u8 head;
__u8 pad03[5];
};
struct nv50_disp_mthd_v1 {
__u8 version;
#define NV50_DISP_MTHD_V1_DAC_PWR 0x10
#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11
#define NV50_DISP_MTHD_V1_SOR_PWR 0x20
#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
#define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24
#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30
__u8 method;
__u16 hasht;
__u16 hashm;
__u8 pad06[2];
};
struct nv50_disp_dac_pwr_v0 {
__u8 version;
__u8 state;
__u8 data;
__u8 vsync;
__u8 hsync;
__u8 pad05[3];
};
#endif #endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册