Commit d02b0ffb authored by Dave Airlie's avatar Dave Airlie

Merge branch 'linux-4.13' of git://github.com/skeggsb/linux into drm-next

- HDMI stereoscopic support
- Rework of display code to properly support SOR pad macro routing on
>=GM20x GPUs
- Various other fixes/improvements.

* 'linux-4.13' of git://github.com/skeggsb/linux: (73 commits)
  drm/nouveau/disp/nv50-: avoid creating ORs that aren't present on HW
  drm/nouveau: use proper prototype in nouveau_pmops_runtime() definition
  drm/nouveau: Skip vga_fini on non-PCI device
  drm/nouveau/tegra: Don't leave GPU in reset
  drm/nouveau/tegra: Skip manual unpowergating when not necessary
  drm/nouveau/hwmon: Change permissions to numeric
  drm/nouveau/hwmon: expose the auto_point and pwm_min/max attrs
  drm/nouveau/hwmon: Remove old code, add .write/.read operations
  drm/nouveau/hwmon: Add nouveau_hwmon_ops structure with .is_visible/.read_string
  drm/nouveau/hwmon: Add config for all sensors and their settings
  drm/nouveau/disp/gm200-: allow non-identity mapping of SOR <-> macro links
  drm/nouveau/disp/nv50-: implement a common supervisor 3.0
  drm/nouveau/disp/nv50-: implement a common supervisor 2.2
  drm/nouveau/disp/nv50-: implement a common supervisor 2.1
  drm/nouveau/disp/nv50-: implement a common supervisor 2.0
  drm/nouveau/disp/nv50-: implement a common supervisor 1.0
  drm/nouveau/disp/nv50-gt21x: remove workaround for dp->tmds hotplug issues
  drm/nouveau/disp/dp: use new devinit script interpreter entry-point
  drm/nouveau/disp/dp: determine link bandwidth requirements from head state
  drm/nouveau/disp: introduce acquire/release display path methods
  ...
parents 4a525bad 7df1bb87
......@@ -169,18 +169,10 @@ static inline void
nouveau_bios_run_init_table(struct drm_device *dev, u16 table,
struct dcb_output *outp, int crtc)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvkm_bios *bios = nvxx_bios(&drm->client.device);
struct nvbios_init init = {
.subdev = &bios->subdev,
.bios = bios,
.offset = table,
.outp = outp,
.crtc = crtc,
.execute = 1,
};
nvbios_exec(&init);
nvbios_init(&nvxx_bios(&nouveau_drm(dev)->client.device)->subdev, table,
init.outp = outp;
init.head = crtc;
);
}
#endif
......@@ -27,29 +27,25 @@ struct nv50_disp_scanoutpos_v0 {
struct nv50_disp_mthd_v1 {
__u8 version;
#define NV50_DISP_MTHD_V1_DAC_PWR 0x10
#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_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_SOR_DP_MST_LINK 0x25
#define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26
#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30
__u8 method;
__u16 hasht;
__u16 hashm;
__u8 pad06[2];
};
struct nv50_disp_dac_pwr_v0 {
struct nv50_disp_acquire_v0 {
__u8 version;
__u8 state;
__u8 data;
__u8 vsync;
__u8 hsync;
__u8 pad05[3];
__u8 or;
__u8 link;
__u8 pad03[5];
};
struct nv50_disp_dac_load_v0 {
......@@ -59,12 +55,6 @@ struct nv50_disp_dac_load_v0 {
__u32 data;
};
struct nv50_disp_sor_pwr_v0 {
__u8 version;
__u8 state;
__u8 pad02[6];
};
struct nv50_disp_sor_hda_eld_v0 {
__u8 version;
__u8 pad01[7];
......@@ -76,7 +66,9 @@ struct nv50_disp_sor_hdmi_pwr_v0 {
__u8 state;
__u8 max_ac_packet;
__u8 rekey;
__u8 pad04[4];
__u8 avi_infoframe_length;
__u8 vendor_infoframe_length;
__u8 pad06[2];
};
struct nv50_disp_sor_lvds_script_v0 {
......@@ -86,12 +78,6 @@ struct nv50_disp_sor_lvds_script_v0 {
__u8 pad04[4];
};
struct nv50_disp_sor_dp_pwr_v0 {
__u8 version;
__u8 state;
__u8 pad02[6];
};
struct nv50_disp_sor_dp_mst_link_v0 {
__u8 version;
__u8 state;
......@@ -106,11 +92,4 @@ struct nv50_disp_sor_dp_mst_vcpi_v0 {
__u16 pbn;
__u16 aligned_pbn;
};
struct nv50_disp_pior_pwr_v0 {
__u8 version;
__u8 state;
__u8 type;
__u8 pad03[5];
};
#endif
......@@ -8,17 +8,15 @@ struct nvkm_disp {
const struct nvkm_disp_func *func;
struct nvkm_engine engine;
struct nvkm_oproxy *client;
struct list_head head;
struct list_head ior;
struct list_head outp;
struct list_head conn;
struct nvkm_event hpd;
struct nvkm_event vblank;
struct {
int nr;
} head;
struct nvkm_oproxy *client;
};
int nv04_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
......@@ -26,7 +24,9 @@ int nv50_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int g84_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gt200_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int g94_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int mcp77_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gt215_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int mcp89_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gf119_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gk104_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
int gk110_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
......
......@@ -3,19 +3,34 @@
struct nvbios_init {
struct nvkm_subdev *subdev;
struct nvkm_bios *bios;
u16 offset;
u32 offset;
struct dcb_output *outp;
int crtc;
int or;
int link;
int head;
/* internal state used during parsing */
u8 execute;
u32 nested;
u16 repeat;
u16 repend;
u32 repeat;
u32 repend;
u32 ramcfg;
};
#define nvbios_init(s,o,ARGS...) ({ \
struct nvbios_init init = { \
.subdev = (s), \
.offset = (o), \
.or = -1, \
.link = 0, \
.head = -1, \
.execute = 1, \
}; \
ARGS \
nvbios_exec(&init); \
})
int nvbios_exec(struct nvbios_init *);
int nvbios_init(struct nvkm_subdev *, bool execute);
int nvbios_post(struct nvkm_subdev *, bool execute);
#endif
......@@ -26,7 +26,6 @@ struct nvkm_timer {
u64 nvkm_timer_read(struct nvkm_timer *);
void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *);
void nvkm_timer_alarm_cancel(struct nvkm_timer *, struct nvkm_alarm *);
/* Delay based on GPU time (ie. PTIMER).
*
......
......@@ -1533,7 +1533,8 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
if (conf & 0x100000)
entry->i2c_upper_default = true;
entry->hasht = (entry->location << 4) | entry->type;
entry->hasht = (entry->extdev << 8) | (entry->location << 4) |
entry->type;
entry->hashm = (entry->heads << 8) | (link << 6) | entry->or;
return true;
}
......
......@@ -1045,6 +1045,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
return MODE_BAD;
}
if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
clock *= 2;
if (clock < min_clock)
return MODE_CLOCK_LOW;
......@@ -1321,6 +1324,13 @@ nouveau_connector_create(struct drm_device *dev, int index)
break;
}
/* HDMI 3D support */
if ((disp->disp.oclass >= G82_DISP)
&& ((type == DRM_MODE_CONNECTOR_DisplayPort)
|| (type == DRM_MODE_CONNECTOR_eDP)
|| (type == DRM_MODE_CONNECTOR_HDMIA)))
connector->stereo_allowed = true;
/* defaults, will get overridden in detect() */
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
......
......@@ -727,7 +727,7 @@ nouveau_pmops_thaw(struct device *dev)
}
bool
nouveau_pmops_runtime()
nouveau_pmops_runtime(void)
{
if (nouveau_runtime_pm == -1)
return nouveau_is_optimus() || nouveau_is_v1_dsm();
......
......@@ -42,6 +42,7 @@ struct nouveau_encoder {
struct dcb_output *dcb;
int or;
int link;
struct i2c_adapter *i2c;
struct nvkm_i2c_aux *aux;
......
This diff is collapsed.
......@@ -111,6 +111,10 @@ nouveau_vga_fini(struct nouveau_drm *drm)
struct drm_device *dev = drm->dev;
bool runtime = nouveau_pmops_runtime();
/* only relevant for PCI devices */
if (!dev->pdev)
return;
vga_client_register(dev->pdev, NULL, NULL, NULL);
if (pci_is_thunderbolt_attached(dev->pdev))
......
This diff is collapsed.
......@@ -1257,7 +1257,7 @@ nvaa_chipset = {
.therm = g84_therm_new,
.timer = nv41_timer_new,
.volt = nv40_volt_new,
.disp = g94_disp_new,
.disp = mcp77_disp_new,
.dma = nv50_dma_new,
.fifo = g84_fifo_new,
.gr = gt200_gr_new,
......@@ -1289,7 +1289,7 @@ nvac_chipset = {
.therm = g84_therm_new,
.timer = nv41_timer_new,
.volt = nv40_volt_new,
.disp = g94_disp_new,
.disp = mcp77_disp_new,
.dma = nv50_dma_new,
.fifo = g84_fifo_new,
.gr = mcp79_gr_new,
......@@ -1323,7 +1323,7 @@ nvaf_chipset = {
.timer = nv41_timer_new,
.volt = nv40_volt_new,
.ce[0] = gt215_ce_new,
.disp = gt215_disp_new,
.disp = mcp89_disp_new,
.dma = nv50_dma_new,
.fifo = g84_fifo_new,
.gr = mcp89_gr_new,
......
......@@ -51,10 +51,12 @@ nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev)
reset_control_assert(tdev->rst);
udelay(10);
ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D);
if (ret)
goto err_clamp;
udelay(10);
if (!tdev->pdev->dev.pm_domain) {
ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D);
if (ret)
goto err_clamp;
udelay(10);
}
reset_control_deassert(tdev->rst);
udelay(10);
......@@ -80,9 +82,6 @@ nvkm_device_tegra_power_down(struct nvkm_device_tegra *tdev)
{
int ret;
reset_control_assert(tdev->rst);
udelay(10);
clk_disable_unprepare(tdev->clk_pwr);
if (tdev->clk_ref)
clk_disable_unprepare(tdev->clk_ref);
......
......@@ -4,7 +4,9 @@ nvkm-y += nvkm/engine/disp/nv50.o
nvkm-y += nvkm/engine/disp/g84.o
nvkm-y += nvkm/engine/disp/g94.o
nvkm-y += nvkm/engine/disp/gt200.o
nvkm-y += nvkm/engine/disp/mcp77.o
nvkm-y += nvkm/engine/disp/gt215.o
nvkm-y += nvkm/engine/disp/mcp89.o
nvkm-y += nvkm/engine/disp/gf119.o
nvkm-y += nvkm/engine/disp/gk104.o
nvkm-y += nvkm/engine/disp/gk110.o
......@@ -12,29 +14,41 @@ nvkm-y += nvkm/engine/disp/gm107.o
nvkm-y += nvkm/engine/disp/gm200.o
nvkm-y += nvkm/engine/disp/gp100.o
nvkm-y += nvkm/engine/disp/gp102.o
nvkm-y += nvkm/engine/disp/vga.o
nvkm-y += nvkm/engine/disp/outp.o
nvkm-y += nvkm/engine/disp/outpdp.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/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/dport.o
nvkm-y += nvkm/engine/disp/conn.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/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/vga.o
nvkm-y += nvkm/engine/disp/conn.o
nvkm-y += nvkm/engine/disp/rootnv04.o
nvkm-y += nvkm/engine/disp/rootnv50.o
......
......@@ -22,6 +22,7 @@
* Authors: Ben Skeggs
*/
#include "dmacnv50.h"
#include "head.h"
#include "rootnv50.h"
#include <core/client.h>
......@@ -50,7 +51,7 @@ nv50_disp_base_new(const struct nv50_disp_dmac_func *func,
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 (args->v0.head > disp->base.head.nr)
if (!nvkm_head_find(&disp->base, args->v0.head))
return -EINVAL;
push = args->v0.pushbuf;
head = args->v0.head;
......
......@@ -25,6 +25,7 @@
#include "rootnv50.h"
#include <core/client.h>
#include <core/notify.h>
#include <core/ramht.h>
#include <engine/dma.h>
......
......@@ -30,9 +30,9 @@
#include <nvif/event.h>
static int
nvkm_connector_hpd(struct nvkm_notify *notify)
nvkm_conn_hpd(struct nvkm_notify *notify)
{
struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
struct nvkm_conn *conn = container_of(notify, typeof(*conn), hpd);
struct nvkm_disp *disp = conn->disp;
struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
const struct nvkm_gpio_ntfy_rep *line = notify->data;
......@@ -52,21 +52,21 @@ nvkm_connector_hpd(struct nvkm_notify *notify)
}
void
nvkm_connector_fini(struct nvkm_connector *conn)
nvkm_conn_fini(struct nvkm_conn *conn)
{
nvkm_notify_put(&conn->hpd);
}
void
nvkm_connector_init(struct nvkm_connector *conn)
nvkm_conn_init(struct nvkm_conn *conn)
{
nvkm_notify_get(&conn->hpd);
}
void
nvkm_connector_del(struct nvkm_connector **pconn)
nvkm_conn_del(struct nvkm_conn **pconn)
{
struct nvkm_connector *conn = *pconn;
struct nvkm_conn *conn = *pconn;
if (conn) {
nvkm_notify_fini(&conn->hpd);
kfree(*pconn);
......@@ -75,8 +75,8 @@ nvkm_connector_del(struct nvkm_connector **pconn)
}
static void
nvkm_connector_ctor(struct nvkm_disp *disp, int index,
struct nvbios_connE *info, struct nvkm_connector *conn)
nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
struct nvkm_conn *conn)
{
static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio;
......@@ -105,7 +105,7 @@ nvkm_connector_ctor(struct nvkm_disp *disp, int index,
return;
}
ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd,
true, &(struct nvkm_gpio_ntfy_req) {
.mask = NVKM_GPIO_TOGGLED,
.line = func.line,
......@@ -122,11 +122,11 @@ nvkm_connector_ctor(struct nvkm_disp *disp, int index,
}
int
nvkm_connector_new(struct nvkm_disp *disp, int index,
struct nvbios_connE *info, struct nvkm_connector **pconn)
nvkm_conn_new(struct nvkm_disp *disp, int index, struct nvbios_connE *info,
struct nvkm_conn **pconn)
{
if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL)))
return -ENOMEM;
nvkm_connector_ctor(disp, index, info, *pconn);
nvkm_conn_ctor(disp, index, info, *pconn);
return 0;
}
......@@ -6,7 +6,7 @@
#include <subdev/bios.h>
#include <subdev/bios/conn.h>
struct nvkm_connector {
struct nvkm_conn {
struct nvkm_disp *disp;
int index;
struct nvbios_connE info;
......@@ -16,14 +16,14 @@ struct nvkm_connector {
struct list_head head;
};
int nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *,
struct nvkm_connector **);
void nvkm_connector_del(struct nvkm_connector **);
void nvkm_connector_init(struct nvkm_connector *);
void nvkm_connector_fini(struct nvkm_connector *);
int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *,
struct nvkm_conn **);
void nvkm_conn_del(struct nvkm_conn **);
void nvkm_conn_init(struct nvkm_conn *);
void nvkm_conn_fini(struct nvkm_conn *);
#define CONN_MSG(c,l,f,a...) do { \
struct nvkm_connector *_conn = (c); \
struct nvkm_conn *_conn = (c); \
nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \
_conn->index, _conn->info.location, _conn->info.type, ##a); \
} while(0)
......
......@@ -22,6 +22,7 @@
* Authors: Ben Skeggs
*/
#include "channv50.h"
#include "head.h"
#include "rootnv50.h"
#include <core/client.h>
......@@ -48,7 +49,7 @@ nv50_disp_curs_new(const struct nv50_disp_chan_func *func,
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create disp cursor vers %d head %d\n",
args->v0.version, args->v0.head);
if (args->v0.head > disp->base.head.nr)
if (!nvkm_head_find(&disp->base, args->v0.head))
return -EINVAL;
head = args->v0.head;
} else
......
/*
* 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)
{
struct nvkm_device *device = disp->engine.subdev.device;
if (!(nvkm_rd32(device, 0x612004) & (0x00000010 << id)))
return 0;
return nvkm_ior_new_(&gf119_dac, disp, DAC, id);
}
......@@ -21,106 +21,96 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "outp.h"
#include "ior.h"
#include <core/client.h>
#include <subdev/timer.h>
#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
nv50_dac_power(NV50_DISP_MTHD_V1)
static void
nv50_dac_clock(struct nvkm_ior *dac)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
const u32 doff = outp->or * 0x800;
union {
struct nv50_disp_dac_pwr_v0 v0;
} *args = data;
u32 stat;
int ret = -ENOSYS;
nvif_ioctl(object, "disp dac pwr size %d\n", size);
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_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;
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
break;
);
nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
break;
);
return 0;
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(NV50_DISP_MTHD_V1)
nv50_dac_sense(struct nvkm_ior *dac, u32 loadval)
{
struct nvkm_subdev *subdev = &disp->base.engine.subdev;
struct nvkm_device *device = subdev->device;
union {
struct nv50_disp_dac_load_v0 v0;
} *args = data;
const u32 doff = outp->or * 0x800;
u32 loadval;
int ret = -ENOSYS;
struct nvkm_device *device = dac->disp->engine.subdev.device;
const u32 doff = nv50_ior_base(dac);
nvif_ioctl(object, "disp dac load size %d\n", size);
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp dac load vers %d data %08x\n",
args->v0.version, args->v0.data);
if (args->v0.data & 0xfff00000)
return -EINVAL;
loadval = args->v0.data;
} else
return ret;
nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80150000);
nvkm_msec(device, 2000,
if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000))
break;
);
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);
nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80550000);
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;
);
}
nvkm_debug(subdev, "DAC%d sense: %08x\n", outp->or, loadval);
if (!(loadval & 0x80000000))
return -ETIMEDOUT;
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;
}
args->v0.load = (loadval & 0x38000000) >> 27;
return 0;
state->head = ctrl & 0x00000003;
}
static const struct nvkm_output_func
nv50_dac_output_func = {
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_output_new(struct nvkm_disp *disp, int index,
struct dcb_output *dcbE, struct nvkm_output **poutp)
nv50_dac_new(struct nvkm_disp *disp, int id)
{
return nvkm_output_new_(&nv50_dac_output_func, disp,
index, dcbE, poutp);
struct nvkm_device *device = disp->engine.subdev.device;
if (!(nvkm_rd32(device, 0x610184) & (0x00100000 << id)))
return 0;
return nvkm_ior_new_(&nv50_dac, disp, DAC, id);
}
This diff is collapsed.
#ifndef __NVKM_DISP_DPORT_H__
#define __NVKM_DISP_DPORT_H__
struct nvkm_output_dp;
#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 {
union {
struct nvkm_outp base;
struct nvkm_outp outp;
};
struct nvbios_dpout info;
u8 version;
struct nvkm_i2c_aux *aux;
struct nvkm_notify hpd;
bool present;
u8 dpcd[16];
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 **);
/* DPCD Receiver Capabilities */
#define DPCD_RC00_DPCD_REV 0x00000
......@@ -76,6 +106,4 @@ struct nvkm_output_dp;
#define DPCD_SC00_SET_POWER 0x03
#define DPCD_SC00_SET_POWER_D0 0x01
#define DPCD_SC00_SET_POWER_D3 0x03
void nvkm_dp_train(struct nvkm_output_dp *);
#endif
This diff is collapsed.
......@@ -22,30 +22,20 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
g84_disp = {
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_intr_supervisor,
.super = nv50_disp_super,
.root = &g84_disp_root_oclass,
.head.vblank_init = nv50_disp_vblank_init,
.head.vblank_fini = nv50_disp_vblank_fini,
.head.scanoutpos = nv50_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.external.tmds = nv50_pior_output_new,
.outp.external.dp = nv50_pior_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 2,
.sor.power = nv50_sor_power,
.sor.hdmi = g84_hdmi_ctrl,
.pior.nr = 3,
.pior.power = nv50_pior_power,
.head.new = nv50_head_new,
.dac = { .nr = 3, .new = nv50_dac_new },
.sor = { .nr = 2, .new = g84_sor_new },
.pior = { .nr = 3, .new = nv50_pior_new },
};
int
......
......@@ -22,31 +22,20 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
g94_disp = {
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_intr_supervisor,
.super = nv50_disp_super,
.root = &g94_disp_root_oclass,
.head.vblank_init = nv50_disp_vblank_init,
.head.vblank_fini = nv50_disp_vblank_fini,
.head.scanoutpos = nv50_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = g94_sor_dp_new,
.outp.external.tmds = nv50_pior_output_new,
.outp.external.dp = nv50_pior_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hdmi = g84_hdmi_ctrl,
.pior.nr = 3,
.pior.power = nv50_pior_power,
.head.new = nv50_head_new,
.dac = { .nr = 3, .new = nv50_dac_new },
.sor = { .nr = 4, .new = g94_sor_new },
.pior = { .nr = 3, .new = nv50_pior_new },
};
int
......
......@@ -22,6 +22,8 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
......@@ -29,22 +31,11 @@ gk104_disp = {
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_intr_supervisor,
.super = gf119_disp_super,
.root = &gk104_disp_root_oclass,
.head.vblank_init = gf119_disp_vblank_init,
.head.vblank_fini = gf119_disp_vblank_fini,
.head.scanoutpos = gf119_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = gf119_sor_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hda_eld = gf119_hda_eld,
.sor.hdmi = gk104_hdmi_ctrl,
.head.new = gf119_head_new,
.dac = { .nr = 3, .new = gf119_dac_new },
.sor = { .nr = 4, .new = gk104_sor_new },
};
int
......
......@@ -22,6 +22,8 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
......@@ -29,22 +31,11 @@ gk110_disp = {
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_intr_supervisor,
.super = gf119_disp_super,
.root = &gk110_disp_root_oclass,
.head.vblank_init = gf119_disp_vblank_init,
.head.vblank_fini = gf119_disp_vblank_fini,
.head.scanoutpos = gf119_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = gf119_sor_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hda_eld = gf119_hda_eld,
.sor.hdmi = gk104_hdmi_ctrl,
.head.new = gf119_head_new,
.dac = { .nr = 3, .new = gf119_dac_new },
.sor = { .nr = 4, .new = gk104_sor_new },
};
int
......
......@@ -22,6 +22,8 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
......@@ -29,22 +31,11 @@ gm107_disp = {
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_intr_supervisor,
.super = gf119_disp_super,
.root = &gm107_disp_root_oclass,
.head.vblank_init = gf119_disp_vblank_init,
.head.vblank_fini = gf119_disp_vblank_fini,
.head.scanoutpos = gf119_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = gm107_sor_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hda_eld = gf119_hda_eld,
.sor.hdmi = gk104_hdmi_ctrl,
.head.new = gf119_head_new,
.dac = { .nr = 3, .new = gf119_dac_new },
.sor = { .nr = 4, .new = gm107_sor_new },
};
int
......
......@@ -22,6 +22,8 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
......@@ -29,23 +31,11 @@ gm200_disp = {
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_intr_supervisor,
.super = gf119_disp_super,
.root = &gm200_disp_root_oclass,
.head.vblank_init = gf119_disp_vblank_init,
.head.vblank_fini = gf119_disp_vblank_fini,
.head.scanoutpos = gf119_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = gm200_sor_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hda_eld = gf119_hda_eld,
.sor.hdmi = gk104_hdmi_ctrl,
.sor.magic = gm200_sor_magic,
.head.new = gf119_head_new,
.dac = { .nr = 3, .new = gf119_dac_new },
.sor = { .nr = 4, .new = gm200_sor_new },
};
int
......
......@@ -22,6 +22,8 @@
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
......@@ -29,23 +31,10 @@ gp100_disp = {
.intr = gf119_disp_intr,
.intr_error = gf119_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_intr_supervisor,
.super = gf119_disp_super,
.root = &gp100_disp_root_oclass,
.head.vblank_init = gf119_disp_vblank_init,
.head.vblank_fini = gf119_disp_vblank_fini,
.head.scanoutpos = gf119_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = gm200_sor_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hda_eld = gf119_hda_eld,
.sor.hdmi = gk104_hdmi_ctrl,
.sor.magic = gm200_sor_magic,
.head.new = gf119_head_new,
.sor = { .nr = 4, .new = gm200_sor_new },
};
int
......
......@@ -22,6 +22,8 @@
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static void
......@@ -55,23 +57,10 @@ gp102_disp = {
.intr = gf119_disp_intr,
.intr_error = gp102_disp_intr_error,
.uevent = &gf119_disp_chan_uevent,
.super = gf119_disp_intr_supervisor,
.super = gf119_disp_super,
.root = &gp102_disp_root_oclass,
.head.vblank_init = gf119_disp_vblank_init,
.head.vblank_fini = gf119_disp_vblank_fini,
.head.scanoutpos = gf119_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = gm200_sor_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hda_eld = gf119_hda_eld,
.sor.hdmi = gk104_hdmi_ctrl,
.sor.magic = gm200_sor_magic,
.head.new = gf119_head_new,
.sor = { .nr = 4, .new = gm200_sor_new },
};
int
......
......@@ -22,30 +22,20 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
gt200_disp = {
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_intr_supervisor,
.super = nv50_disp_super,
.root = &gt200_disp_root_oclass,
.head.vblank_init = nv50_disp_vblank_init,
.head.vblank_fini = nv50_disp_vblank_fini,
.head.scanoutpos = nv50_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.external.tmds = nv50_pior_output_new,
.outp.external.dp = nv50_pior_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 2,
.sor.power = nv50_sor_power,
.sor.hdmi = g84_hdmi_ctrl,
.pior.nr = 3,
.pior.power = nv50_pior_power,
.head.new = nv50_head_new,
.dac = { .nr = 3, .new = nv50_dac_new },
.sor = { .nr = 2, .new = g84_sor_new },
.pior = { .nr = 3, .new = nv50_pior_new },
};
int
......
......@@ -22,32 +22,20 @@
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "head.h"
#include "ior.h"
#include "rootnv50.h"
static const struct nv50_disp_func
gt215_disp = {
.intr = nv50_disp_intr,
.uevent = &nv50_disp_chan_uevent,
.super = nv50_disp_intr_supervisor,
.super = nv50_disp_super,
.root = &gt215_disp_root_oclass,
.head.vblank_init = nv50_disp_vblank_init,
.head.vblank_fini = nv50_disp_vblank_fini,
.head.scanoutpos = nv50_disp_root_scanoutpos,
.outp.internal.crt = nv50_dac_output_new,
.outp.internal.tmds = nv50_sor_output_new,
.outp.internal.lvds = nv50_sor_output_new,
.outp.internal.dp = g94_sor_dp_new,
.outp.external.tmds = nv50_pior_output_new,
.outp.external.dp = nv50_pior_dp_new,
.dac.nr = 3,
.dac.power = nv50_dac_power,
.dac.sense = nv50_dac_sense,
.sor.nr = 4,
.sor.power = nv50_sor_power,
.sor.hda_eld = gt215_hda_eld,
.sor.hdmi = gt215_hdmi_ctrl,
.pior.nr = 3,
.pior.power = nv50_pior_power,
.head.new = nv50_head_new,
.dac = { .nr = 3, .new = nv50_dac_new },
.sor = { .nr = 4, .new = gt215_sor_new },
.pior = { .nr = 3, .new = nv50_pior_new },
};
int
......
......@@ -21,63 +21,34 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "outp.h"
#include "ior.h"
#include <core/client.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/timer.h>
#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
gf119_hda_eld(NV50_DISP_MTHD_V1)
void
gf119_hda_eld(struct nvkm_ior *ior, u8 *data, u8 size)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
union {
struct nv50_disp_sor_hda_eld_v0 v0;
} *args = data;
const u32 soff = outp->or * 0x030;
const u32 hoff = head * 0x800;
int ret = -ENOSYS, i;
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = 0x030 * ior->id;
int i;
nvif_ioctl(object, "disp sor hda eld size %d\n", size);
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "disp sor hda eld vers %d\n",
args->v0.version);
if (size > 0x60)
return -E2BIG;
} else
return ret;
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);
}
if (size && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP) {
nvkm_mask(device, 0x616618 + hoff, 0x8000000c, 0x80000001);
nvkm_msec(device, 2000,
u32 tmp = nvkm_rd32(device, 0x616618 + hoff);
if (!(tmp & 0x80000000))
break;
);
}
void
gf119_hda_hpd(struct nvkm_ior *ior, int head, bool present)
{
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 hoff = 0x800 * head;
u32 data = 0x80000000;
u32 mask = 0x80000001;
if (present) {
nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000);
for (i = 0; i < size; i++)
nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
for (; i < 0x60; i++)
nvkm_wr32(device, 0x10ec00 + soff, (i << 8));
nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000003);
data |= 0x00000001;
} else {
if (outp->info.type == DCB_OUTPUT_DP) {
nvkm_mask(device, 0x616618 + hoff, 0x80000001, 0x80000000);
nvkm_msec(device, 2000,
u32 tmp = nvkm_rd32(device, 0x616618 + hoff);
if (!(tmp & 0x80000000))
break;
);
}
nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
mask |= 0x00000002;
}
return 0;
nvkm_mask(device, 0x10ec10 + ior->id * 0x030, mask, data);
}
......@@ -21,59 +21,31 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "outp.h"
#include "ior.h"
#include <core/client.h>
#include <subdev/timer.h>
#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
gt215_hda_eld(NV50_DISP_MTHD_V1)
void
gt215_hda_eld(struct nvkm_ior *ior, u8 *data, u8 size)
{
struct nvkm_device *device = disp->base.engine.subdev.device;
union {
struct nv50_disp_sor_hda_eld_v0 v0;
} *args = data;
const u32 soff = outp->or * 0x800;
int ret = -ENOSYS, i;
nvif_ioctl(object, "disp sor hda eld size %d\n", size);
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) {
nvif_ioctl(object, "disp sor hda eld vers %d\n",
args->v0.version);
if (size > 0x60)
return -E2BIG;
} else
return ret;
struct nvkm_device *device = ior->disp->engine.subdev.device;
const u32 soff = ior->id * 0x800;
int i;
if (size && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP) {
nvkm_mask(device, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
nvkm_msec(device, 2000,
u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff);
if (!(tmp & 0x80000000))
break;
);
}
for (i = 0; i < size; i++)
nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[i]);
for (; i < 0x60; i++)
nvkm_wr32(device, 0x61c440 + soff, (i << 8));
nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003);
} else {
if (outp->info.type == DCB_OUTPUT_DP) {
nvkm_mask(device, 0x61c1e0 + soff, 0x80000001, 0x80000000);
nvkm_msec(device, 2000,
u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff);
if (!(tmp & 0x80000000))
break;
);
}
nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
}
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);
}
return 0;
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);
}
#include "hdmi.h"
void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame,
u8 *raw_frame, ssize_t len)
{
u32 header = 0;
u32 subpack0_low = 0;
u32 subpack0_high = 0;
u32 subpack1_low = 0;
u32 subpack1_high = 0;
switch (len) {
/*
* "When in doubt, use brute force."
* -- Ken Thompson.
*/
default:
/*
* We presume that no valid frame is longer than 17
* octets, including header... And truncate to that
* if it's longer.
*/
case 17:
subpack1_high = (raw_frame[16] << 16);
case 16:
subpack1_high |= (raw_frame[15] << 8);
case 15:
subpack1_high |= raw_frame[14];
case 14:
subpack1_low = (raw_frame[13] << 24);
case 13:
subpack1_low |= (raw_frame[12] << 16);
case 12:
subpack1_low |= (raw_frame[11] << 8);
case 11:
subpack1_low |= raw_frame[10];
case 10:
subpack0_high = (raw_frame[9] << 16);
case 9:
subpack0_high |= (raw_frame[8] << 8);
case 8:
subpack0_high |= raw_frame[7];
case 7:
subpack0_low = (raw_frame[6] << 24);
case 6:
subpack0_low |= (raw_frame[5] << 16);
case 5:
subpack0_low |= (raw_frame[4] << 8);
case 4:
subpack0_low |= raw_frame[3];
case 3:
header = (raw_frame[2] << 16);
case 2:
header |= (raw_frame[1] << 8);
case 1:
header |= raw_frame[0];
case 0:
break;
}
packed_frame->header = header;
packed_frame->subpack0_low = subpack0_low;
packed_frame->subpack0_high = subpack0_high;
packed_frame->subpack1_low = subpack1_low;
packed_frame->subpack1_high = subpack1_high;
}
#ifndef __NVKM_DISP_HDMI_H__
#define __NVKM_DISP_HDMI_H__
#include "ior.h"
struct packed_hdmi_infoframe {
u32 header;
u32 subpack0_low;
u32 subpack0_high;
u32 subpack1_low;
u32 subpack1_high;
};
void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame,
u8 *raw_frame, ssize_t len);
#endif
......@@ -21,54 +21,42 @@
*
* Authors: Ben Skeggs
*/
#include "nv50.h"
#include "hdmi.h"
#include <core/client.h>
#include <nvif/cl5070.h>
#include <nvif/unpack.h>
int
g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
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 = disp->base.engine.subdev.device;
const u32 hoff = (head * 0x800);
union {
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
int ret = -ENOSYS;
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;
nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
args->v0.max_ac_packet, args->v0.rekey);
if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
return -EINVAL;
ctrl = 0x40000000 * !!args->v0.state;
ctrl |= args->v0.max_ac_packet << 16;
ctrl |= args->v0.rekey;
ctrl |= 0x1f000000; /* ??? */
} else
return ret;
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 0;
return;
}
/* AVI InfoFrame */
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000);
nvkm_wr32(device, 0x616528 + hoff, 0x000d0282);
nvkm_wr32(device, 0x61652c + hoff, 0x0000006f);
nvkm_wr32(device, 0x616530 + hoff, 0x00000000);
nvkm_wr32(device, 0x616534 + hoff, 0x00000000);
nvkm_wr32(device, 0x616538 + hoff, 0x00000000);
nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001);
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);
......@@ -77,6 +65,18 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
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 */
......@@ -88,5 +88,4 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
/* HDMI_CTRL */
nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment