Commit 1a92b7a2 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'linux-3.19' of git://anongit.freedesktop.org/git/nouveau/linux-2.6 into drm-next

- Tegra K1 voltage support, and coherency improvements
- GM204 support (modesetting, still waiting on NVIDIA for signed fw to
proceed further), and a lot of bios/i2c/devinit adjustments needed to
support it
- GT21x memory reclocking work
- Various other bits and pieces, most of which are prep-work for a
couple of bigger projects I didn't get finished in time

* 'linux-3.19' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (73 commits)
  drm/nv50/kms: drop requirement that framebuffer bos be contig up-front
  drm/nv50/kms: directly use cursor image from userspace buffer
  drm/nouveau/kms: when pinning display-related buffers, force contig vram
  drm/nouveau: teach nouveau_bo_pin() how to force a contig vram allocation
  drm/nouveau/volt: add support for GK20A
  drm/nouveau/platform: add GPU speedo information to nouveau platform
  drm/nouveau/volt: allow non-bios voltage scaling
  drm/gf100-/gr: return non-fatal error code when fw not present
  drm/nouveau/devinit: bump priv ring timeouts before executing scripts
  drm/nouveau/bios: translate ramcfg strap through M0203
  drm/nouveau/fb: make use of M0203 routines for ram type determination
  drm/nouveau/bios: add parsing of BIT M(v2) +0x03 table
  drm/nouveau/core: allow vbios parsing without knowing chipset type
  drm/nouveau/lib: add null backend
  drm/nouveau/device: store revision
  drm/nouveau/core: add some forgotten subdevs to disable mask
  drm/gk20a/clk: fix max VCO value
  drm/nouveau: we need pin_refcnt for nouveau_bo_placement_set()
  drm/nv50-/kms: add some evo tracing ability for debugging
  drm/nv50/kms: use sclass() instead of trial-and-error
  ...
parents 5a52b1f2 9f6d2ce3
...@@ -41,17 +41,28 @@ nouveau-y += core/subdev/bios/extdev.o ...@@ -41,17 +41,28 @@ nouveau-y += core/subdev/bios/extdev.o
nouveau-y += core/subdev/bios/fan.o nouveau-y += core/subdev/bios/fan.o
nouveau-y += core/subdev/bios/gpio.o nouveau-y += core/subdev/bios/gpio.o
nouveau-y += core/subdev/bios/i2c.o nouveau-y += core/subdev/bios/i2c.o
nouveau-y += core/subdev/bios/image.o
nouveau-y += core/subdev/bios/init.o nouveau-y += core/subdev/bios/init.o
nouveau-y += core/subdev/bios/mxm.o nouveau-y += core/subdev/bios/mxm.o
nouveau-y += core/subdev/bios/npde.o
nouveau-y += core/subdev/bios/pcir.o
nouveau-y += core/subdev/bios/perf.o nouveau-y += core/subdev/bios/perf.o
nouveau-y += core/subdev/bios/pll.o nouveau-y += core/subdev/bios/pll.o
nouveau-y += core/subdev/bios/pmu.o
nouveau-y += core/subdev/bios/ramcfg.o nouveau-y += core/subdev/bios/ramcfg.o
nouveau-y += core/subdev/bios/rammap.o nouveau-y += core/subdev/bios/rammap.o
nouveau-y += core/subdev/bios/shadow.o
nouveau-y += core/subdev/bios/shadowacpi.o
nouveau-y += core/subdev/bios/shadowof.o
nouveau-y += core/subdev/bios/shadowpci.o
nouveau-y += core/subdev/bios/shadowramin.o
nouveau-y += core/subdev/bios/shadowrom.o
nouveau-y += core/subdev/bios/timing.o nouveau-y += core/subdev/bios/timing.o
nouveau-y += core/subdev/bios/therm.o nouveau-y += core/subdev/bios/therm.o
nouveau-y += core/subdev/bios/vmap.o nouveau-y += core/subdev/bios/vmap.o
nouveau-y += core/subdev/bios/volt.o nouveau-y += core/subdev/bios/volt.o
nouveau-y += core/subdev/bios/xpio.o nouveau-y += core/subdev/bios/xpio.o
nouveau-y += core/subdev/bios/M0203.o
nouveau-y += core/subdev/bios/M0205.o nouveau-y += core/subdev/bios/M0205.o
nouveau-y += core/subdev/bios/M0209.o nouveau-y += core/subdev/bios/M0209.o
nouveau-y += core/subdev/bios/P0260.o nouveau-y += core/subdev/bios/P0260.o
...@@ -86,6 +97,7 @@ nouveau-y += core/subdev/devinit/nva3.o ...@@ -86,6 +97,7 @@ nouveau-y += core/subdev/devinit/nva3.o
nouveau-y += core/subdev/devinit/nvaf.o nouveau-y += core/subdev/devinit/nvaf.o
nouveau-y += core/subdev/devinit/nvc0.o nouveau-y += core/subdev/devinit/nvc0.o
nouveau-y += core/subdev/devinit/gm107.o nouveau-y += core/subdev/devinit/gm107.o
nouveau-y += core/subdev/devinit/gm204.o
nouveau-y += core/subdev/fb/base.o nouveau-y += core/subdev/fb/base.o
nouveau-y += core/subdev/fb/nv04.o nouveau-y += core/subdev/fb/nv04.o
nouveau-y += core/subdev/fb/nv10.o nouveau-y += core/subdev/fb/nv10.o
...@@ -129,6 +141,7 @@ nouveau-y += core/subdev/fb/ramgk20a.o ...@@ -129,6 +141,7 @@ nouveau-y += core/subdev/fb/ramgk20a.o
nouveau-y += core/subdev/fb/ramgm107.o nouveau-y += core/subdev/fb/ramgm107.o
nouveau-y += core/subdev/fb/sddr2.o nouveau-y += core/subdev/fb/sddr2.o
nouveau-y += core/subdev/fb/sddr3.o nouveau-y += core/subdev/fb/sddr3.o
nouveau-y += core/subdev/fb/gddr3.o
nouveau-y += core/subdev/fb/gddr5.o nouveau-y += core/subdev/fb/gddr5.o
nouveau-y += core/subdev/fuse/base.o nouveau-y += core/subdev/fuse/base.o
nouveau-y += core/subdev/fuse/g80.o nouveau-y += core/subdev/fuse/g80.o
...@@ -147,6 +160,7 @@ nouveau-y += core/subdev/i2c/bit.o ...@@ -147,6 +160,7 @@ nouveau-y += core/subdev/i2c/bit.o
nouveau-y += core/subdev/i2c/pad.o nouveau-y += core/subdev/i2c/pad.o
nouveau-y += core/subdev/i2c/padnv04.o nouveau-y += core/subdev/i2c/padnv04.o
nouveau-y += core/subdev/i2c/padnv94.o nouveau-y += core/subdev/i2c/padnv94.o
nouveau-y += core/subdev/i2c/padgm204.o
nouveau-y += core/subdev/i2c/nv04.o nouveau-y += core/subdev/i2c/nv04.o
nouveau-y += core/subdev/i2c/nv4e.o nouveau-y += core/subdev/i2c/nv4e.o
nouveau-y += core/subdev/i2c/nv50.o nouveau-y += core/subdev/i2c/nv50.o
...@@ -154,6 +168,7 @@ nouveau-y += core/subdev/i2c/nv94.o ...@@ -154,6 +168,7 @@ nouveau-y += core/subdev/i2c/nv94.o
nouveau-y += core/subdev/i2c/nvd0.o nouveau-y += core/subdev/i2c/nvd0.o
nouveau-y += core/subdev/i2c/gf117.o nouveau-y += core/subdev/i2c/gf117.o
nouveau-y += core/subdev/i2c/nve0.o nouveau-y += core/subdev/i2c/nve0.o
nouveau-y += core/subdev/i2c/gm204.o
nouveau-y += core/subdev/ibus/nvc0.o nouveau-y += core/subdev/ibus/nvc0.o
nouveau-y += core/subdev/ibus/nve0.o nouveau-y += core/subdev/ibus/nve0.o
nouveau-y += core/subdev/ibus/gk20a.o nouveau-y += core/subdev/ibus/gk20a.o
...@@ -211,6 +226,7 @@ nouveau-y += core/subdev/vm/nvc0.o ...@@ -211,6 +226,7 @@ nouveau-y += core/subdev/vm/nvc0.o
nouveau-y += core/subdev/volt/base.o nouveau-y += core/subdev/volt/base.o
nouveau-y += core/subdev/volt/gpio.o nouveau-y += core/subdev/volt/gpio.o
nouveau-y += core/subdev/volt/nv40.o nouveau-y += core/subdev/volt/nv40.o
nouveau-y += core/subdev/volt/gk20a.o
nouveau-y += core/engine/falcon.o nouveau-y += core/engine/falcon.o
nouveau-y += core/engine/xtensa.o nouveau-y += core/engine/xtensa.o
...@@ -254,6 +270,7 @@ nouveau-y += core/engine/disp/nvd0.o ...@@ -254,6 +270,7 @@ nouveau-y += core/engine/disp/nvd0.o
nouveau-y += core/engine/disp/nve0.o nouveau-y += core/engine/disp/nve0.o
nouveau-y += core/engine/disp/nvf0.o nouveau-y += core/engine/disp/nvf0.o
nouveau-y += core/engine/disp/gm107.o nouveau-y += core/engine/disp/gm107.o
nouveau-y += core/engine/disp/gm204.o
nouveau-y += core/engine/disp/dacnv50.o nouveau-y += core/engine/disp/dacnv50.o
nouveau-y += core/engine/disp/dport.o nouveau-y += core/engine/disp/dport.o
nouveau-y += core/engine/disp/hdanva3.o nouveau-y += core/engine/disp/hdanva3.o
...@@ -266,6 +283,7 @@ nouveau-y += core/engine/disp/piornv50.o ...@@ -266,6 +283,7 @@ nouveau-y += core/engine/disp/piornv50.o
nouveau-y += core/engine/disp/sornv50.o nouveau-y += core/engine/disp/sornv50.o
nouveau-y += core/engine/disp/sornv94.o nouveau-y += core/engine/disp/sornv94.o
nouveau-y += core/engine/disp/sornvd0.o nouveau-y += core/engine/disp/sornvd0.o
nouveau-y += core/engine/disp/sorgm204.o
nouveau-y += core/engine/disp/vga.o nouveau-y += core/engine/disp/vga.o
nouveau-y += core/engine/fifo/base.o nouveau-y += core/engine/fifo/base.o
nouveau-y += core/engine/fifo/nv04.o nouveau-y += core/engine/fifo/nv04.o
......
...@@ -222,116 +222,3 @@ nouveau_handle_put(struct nouveau_handle *handle) ...@@ -222,116 +222,3 @@ nouveau_handle_put(struct nouveau_handle *handle)
if (handle) if (handle)
nouveau_namedb_put(handle); nouveau_namedb_put(handle);
} }
int
nouveau_handle_new(struct nouveau_object *client, u32 _parent, u32 _handle,
u16 _oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_object *parent = NULL;
struct nouveau_object *engctx = NULL;
struct nouveau_object *object = NULL;
struct nouveau_object *engine;
struct nouveau_oclass *oclass;
struct nouveau_handle *handle;
int ret;
/* lookup parent object and ensure it *is* a parent */
parent = nouveau_handle_ref(client, _parent);
if (!parent) {
nv_error(client, "parent 0x%08x not found\n", _parent);
return -ENOENT;
}
if (!nv_iclass(parent, NV_PARENT_CLASS)) {
nv_error(parent, "cannot have children\n");
ret = -EINVAL;
goto fail_class;
}
/* check that parent supports the requested subclass */
ret = nouveau_parent_sclass(parent, _oclass, &engine, &oclass);
if (ret) {
nv_debug(parent, "illegal class 0x%04x\n", _oclass);
goto fail_class;
}
/* make sure engine init has been completed *before* any objects
* it controls are created - the constructors may depend on
* state calculated at init (ie. default context construction)
*/
if (engine) {
ret = nouveau_object_inc(engine);
if (ret)
goto fail_class;
}
/* if engine requires it, create a context object to insert
* between the parent and its children (eg. PGRAPH context)
*/
if (engine && nv_engine(engine)->cclass) {
ret = nouveau_object_ctor(parent, engine,
nv_engine(engine)->cclass,
data, size, &engctx);
if (ret)
goto fail_engctx;
} else {
nouveau_object_ref(parent, &engctx);
}
/* finally, create new object and bind it to its handle */
ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
*pobject = object;
if (ret)
goto fail_ctor;
ret = nouveau_object_inc(object);
if (ret)
goto fail_init;
ret = nouveau_handle_create(parent, _parent, _handle, object, &handle);
if (ret)
goto fail_handle;
ret = nouveau_handle_init(handle);
if (ret)
nouveau_handle_destroy(handle);
fail_handle:
nouveau_object_dec(object, false);
fail_init:
nouveau_object_ref(NULL, &object);
fail_ctor:
nouveau_object_ref(NULL, &engctx);
fail_engctx:
if (engine)
nouveau_object_dec(engine, false);
fail_class:
nouveau_object_ref(NULL, &parent);
return ret;
}
int
nouveau_handle_del(struct nouveau_object *client, u32 _parent, u32 _handle)
{
struct nouveau_object *parent = NULL;
struct nouveau_object *namedb = NULL;
struct nouveau_handle *handle = NULL;
parent = nouveau_handle_ref(client, _parent);
if (!parent)
return -ENOENT;
namedb = nv_pclass(parent, NV_NAMEDB_CLASS);
if (namedb) {
handle = nouveau_namedb_get(nv_namedb(namedb), _handle);
if (handle) {
nouveau_namedb_put(handle);
nouveau_handle_fini(handle, false);
nouveau_handle_destroy(handle);
}
}
nouveau_object_ref(NULL, &parent);
return handle ? 0 : -EINVAL;
}
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <nvif/unpack.h> #include <nvif/unpack.h>
#include <nvif/class.h> #include <nvif/class.h>
#include <subdev/bios.h>
#include <subdev/fb.h> #include <subdev/fb.h>
#include <subdev/instmem.h> #include <subdev/instmem.h>
...@@ -138,7 +139,7 @@ nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size) ...@@ -138,7 +139,7 @@ nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size)
} }
args->v0.chipset = device->chipset; args->v0.chipset = device->chipset;
args->v0.revision = device->chipset >= 0x10 ? nv_rd32(device, 0) : 0x00; args->v0.revision = device->chiprev;
if (pfb) args->v0.ram_size = args->v0.ram_user = pfb->ram->size; if (pfb) args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
else args->v0.ram_size = args->v0.ram_user = 0; else args->v0.ram_size = args->v0.ram_user = 0;
if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved; if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
...@@ -222,6 +223,7 @@ static const u64 disable_map[] = { ...@@ -222,6 +223,7 @@ static const u64 disable_map[] = {
[NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE, [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE, [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE, [NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_SUBDEV_FUSE] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE, [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE, [NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE,
[NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO, [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO,
...@@ -235,6 +237,7 @@ static const u64 disable_map[] = { ...@@ -235,6 +237,7 @@ static const u64 disable_map[] = {
[NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP, [NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP,
[NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0, [NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0,
[NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1, [NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1,
[NVDEV_ENGINE_COPY2] = NV_DEVICE_V0_DISABLE_COPY1,
[NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC, [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC,
[NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC, [NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC,
[NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP, [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP,
...@@ -352,12 +355,14 @@ nouveau_devobj_ctor(struct nouveau_object *parent, ...@@ -352,12 +355,14 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
/* determine chipset and derive architecture from it */ /* determine chipset and derive architecture from it */
if ((boot0 & 0x1f000000) > 0) { if ((boot0 & 0x1f000000) > 0) {
device->chipset = (boot0 & 0x1ff00000) >> 20; device->chipset = (boot0 & 0x1ff00000) >> 20;
device->chiprev = (boot0 & 0x000000ff);
switch (device->chipset & 0x1f0) { switch (device->chipset & 0x1f0) {
case 0x010: { case 0x010: {
if (0x461 & (1 << (device->chipset & 0xf))) if (0x461 & (1 << (device->chipset & 0xf)))
device->card_type = NV_10; device->card_type = NV_10;
else else
device->card_type = NV_11; device->card_type = NV_11;
device->chiprev = 0x00;
break; break;
} }
case 0x020: device->card_type = NV_20; break; case 0x020: device->card_type = NV_20; break;
...@@ -373,7 +378,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent, ...@@ -373,7 +378,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
case 0x0e0: case 0x0e0:
case 0x0f0: case 0x0f0:
case 0x100: device->card_type = NV_E0; break; case 0x100: device->card_type = NV_E0; break;
case 0x110: device->card_type = GM100; break; case 0x110:
case 0x120: device->card_type = GM100; break;
default: default:
break; break;
} }
...@@ -427,6 +433,10 @@ nouveau_devobj_ctor(struct nouveau_object *parent, ...@@ -427,6 +433,10 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
} }
nv_debug(device, "crystal freq: %dKHz\n", device->crystal); nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
} else
if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) {
device->cname = "NULL";
device->oclass[NVDEV_SUBDEV_VBIOS] = &nouveau_bios_oclass;
} }
if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
......
...@@ -96,6 +96,49 @@ gm100_identify(struct nouveau_device *device) ...@@ -96,6 +96,49 @@ gm100_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
#endif
break;
case 0x124:
device->cname = "GM204";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass;
#if 0
/* looks to be some non-trivial changes */
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
/* priv ring says no to 0x10eb14 writes */
device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass;
#endif
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass;
device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
#if 0
device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
#endif
device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
#if 0
device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass;
#endif
device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass;
#if 0
device->oclass[NVDEV_ENGINE_COPY0 ] = &gm204_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &gm204_copy1_oclass;
device->oclass[NVDEV_ENGINE_COPY2 ] = &gm204_copy2_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
#endif #endif
break; break;
default: default:
......
...@@ -179,6 +179,7 @@ nve0_identify(struct nouveau_device *device) ...@@ -179,6 +179,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass;
device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass;
break; break;
case 0xf0: case 0xf0:
device->cname = "GK110"; device->cname = "GK110";
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <subdev/bios/init.h> #include <subdev/bios/init.h>
#include <subdev/i2c.h> #include <subdev/i2c.h>
#include <engine/disp.h> #include "nv50.h"
#include <nvif/class.h> #include <nvif/class.h>
...@@ -326,7 +326,7 @@ void ...@@ -326,7 +326,7 @@ void
nouveau_dp_train(struct work_struct *w) nouveau_dp_train(struct work_struct *w)
{ {
struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
struct nouveau_disp *disp = nouveau_disp(outp); struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const struct dp_rates *cfg = nouveau_dp_rates; const struct dp_rates *cfg = nouveau_dp_rates;
struct dp_state _dp = { struct dp_state _dp = {
.outp = outp, .outp = outp,
...@@ -334,8 +334,11 @@ nouveau_dp_train(struct work_struct *w) ...@@ -334,8 +334,11 @@ nouveau_dp_train(struct work_struct *w)
u32 datarate = 0; u32 datarate = 0;
int ret; int ret;
if (!outp->base.info.location && priv->sor.magic)
priv->sor.magic(&outp->base);
/* bring capabilities within encoder limits */ /* bring capabilities within encoder limits */
if (nv_mclass(disp) < GF110_DISP) if (nv_mclass(priv) < GF110_DISP)
outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
......
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
static struct nouveau_oclass static struct nouveau_oclass
gm107_disp_sclass[] = { gm107_disp_sclass[] = {
{ GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, { GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
...@@ -44,8 +44,8 @@ gm107_disp_sclass[] = { ...@@ -44,8 +44,8 @@ gm107_disp_sclass[] = {
}; };
static struct nouveau_oclass static struct nouveau_oclass
gm107_disp_base_oclass[] = { gm107_disp_main_oclass[] = {
{ GM107_DISP, &nvd0_disp_base_ofuncs }, { GM107_DISP, &nvd0_disp_main_ofuncs },
{} {}
}; };
...@@ -72,7 +72,7 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -72,7 +72,7 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = gm107_disp_base_oclass; nv_engine(priv)->sclass = gm107_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr; nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
...@@ -99,9 +99,9 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { ...@@ -99,9 +99,9 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nvd0_disp_vblank_func, .base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_core_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_base_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos, .head.scanoutpos = nvd0_disp_main_scanoutpos,
}.base.base; }.base.base;
/*
* 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 <engine/software.h>
#include <engine/disp.h>
#include <nvif/class.h>
#include "nv50.h"
/*******************************************************************************
* Base display object
******************************************************************************/
static struct nouveau_oclass
gm204_disp_sclass[] = {
{ GM204_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
{}
};
static struct nouveau_oclass
gm204_disp_main_oclass[] = {
{ GM204_DISP, &nvd0_disp_main_ofuncs },
{}
};
/*******************************************************************************
* Display engine implementation
******************************************************************************/
static int
gm204_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_disp_priv *priv;
int heads = nv_rd32(parent, 0x022448);
int ret;
ret = nouveau_disp_create(parent, engine, oclass, heads,
"PDISP", "display", &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = gm204_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
priv->sclass = gm204_disp_sclass;
priv->head.nr = heads;
priv->dac.nr = 3;
priv->sor.nr = 4;
priv->dac.power = nv50_dac_power;
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.magic = gm204_sor_magic;
return 0;
}
struct nouveau_oclass *
gm204_disp_outp_sclass[] = {
&gm204_sor_dp_impl.base.base,
NULL
};
struct nouveau_oclass *
gm204_disp_oclass = &(struct nv50_disp_impl) {
.base.base.handle = NV_ENGINE(DISP, 0x07),
.base.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = gm204_disp_ctor,
.dtor = _nouveau_disp_dtor,
.init = _nouveau_disp_init,
.fini = _nouveau_disp_fini,
},
.base.vblank = &nvd0_disp_vblank_func,
.base.outp = gm204_disp_outp_sclass,
.mthd.core = &nve0_disp_core_mthd_chan,
.mthd.base = &nvd0_disp_base_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_main_scanoutpos,
}.base.base;
...@@ -88,12 +88,14 @@ nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) ...@@ -88,12 +88,14 @@ nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{ {
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index); nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
nv_wr32(priv, 0x610020, 0x00000001 << index);
} }
static void static void
nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{ {
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_wr32(priv, 0x610020, 0x00000001 << index);
nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index); nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
} }
...@@ -374,7 +376,7 @@ nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head, ...@@ -374,7 +376,7 @@ nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
} }
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nv50_disp_mast_mthd_base = { nv50_disp_core_mthd_base = {
.mthd = 0x0000, .mthd = 0x0000,
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
...@@ -387,7 +389,7 @@ nv50_disp_mast_mthd_base = { ...@@ -387,7 +389,7 @@ nv50_disp_mast_mthd_base = {
}; };
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nv50_disp_mast_mthd_dac = { nv50_disp_core_mthd_dac = {
.mthd = 0x0080, .mthd = 0x0080,
.addr = 0x000008, .addr = 0x000008,
.data = { .data = {
...@@ -399,7 +401,7 @@ nv50_disp_mast_mthd_dac = { ...@@ -399,7 +401,7 @@ nv50_disp_mast_mthd_dac = {
}; };
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nv50_disp_mast_mthd_sor = { nv50_disp_core_mthd_sor = {
.mthd = 0x0040, .mthd = 0x0040,
.addr = 0x000008, .addr = 0x000008,
.data = { .data = {
...@@ -409,7 +411,7 @@ nv50_disp_mast_mthd_sor = { ...@@ -409,7 +411,7 @@ nv50_disp_mast_mthd_sor = {
}; };
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nv50_disp_mast_mthd_pior = { nv50_disp_core_mthd_pior = {
.mthd = 0x0040, .mthd = 0x0040,
.addr = 0x000008, .addr = 0x000008,
.data = { .data = {
...@@ -419,7 +421,7 @@ nv50_disp_mast_mthd_pior = { ...@@ -419,7 +421,7 @@ nv50_disp_mast_mthd_pior = {
}; };
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nv50_disp_mast_mthd_head = { nv50_disp_core_mthd_head = {
.mthd = 0x0400, .mthd = 0x0400,
.addr = 0x000540, .addr = 0x000540,
.data = { .data = {
...@@ -466,21 +468,21 @@ nv50_disp_mast_mthd_head = { ...@@ -466,21 +468,21 @@ nv50_disp_mast_mthd_head = {
}; };
static const struct nv50_disp_mthd_chan static const struct nv50_disp_mthd_chan
nv50_disp_mast_mthd_chan = { nv50_disp_core_mthd_chan = {
.name = "Core", .name = "Core",
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
{ "Global", 1, &nv50_disp_mast_mthd_base }, { "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &nv50_disp_mast_mthd_dac }, { "DAC", 3, &nv50_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_mast_mthd_sor }, { "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_mast_mthd_pior }, { "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &nv50_disp_mast_mthd_head }, { "HEAD", 2, &nv50_disp_core_mthd_head },
{} {}
} }
}; };
int int
nv50_disp_mast_ctor(struct nouveau_object *parent, nv50_disp_core_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject) struct nouveau_object **pobject)
...@@ -509,7 +511,7 @@ nv50_disp_mast_ctor(struct nouveau_object *parent, ...@@ -509,7 +511,7 @@ nv50_disp_mast_ctor(struct nouveau_object *parent,
} }
static int static int
nv50_disp_mast_init(struct nouveau_object *object) nv50_disp_core_init(struct nouveau_object *object)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_dmac *mast = (void *)object; struct nv50_disp_dmac *mast = (void *)object;
...@@ -546,7 +548,7 @@ nv50_disp_mast_init(struct nouveau_object *object) ...@@ -546,7 +548,7 @@ nv50_disp_mast_init(struct nouveau_object *object)
} }
static int static int
nv50_disp_mast_fini(struct nouveau_object *object, bool suspend) nv50_disp_core_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_dmac *mast = (void *)object; struct nv50_disp_dmac *mast = (void *)object;
...@@ -567,11 +569,11 @@ nv50_disp_mast_fini(struct nouveau_object *object, bool suspend) ...@@ -567,11 +569,11 @@ nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
} }
struct nv50_disp_chan_impl struct nv50_disp_chan_impl
nv50_disp_mast_ofuncs = { nv50_disp_core_ofuncs = {
.base.ctor = nv50_disp_mast_ctor, .base.ctor = nv50_disp_core_ctor,
.base.dtor = nv50_disp_dmac_dtor, .base.dtor = nv50_disp_dmac_dtor,
.base.init = nv50_disp_mast_init, .base.init = nv50_disp_core_init,
.base.fini = nv50_disp_mast_fini, .base.fini = nv50_disp_core_fini,
.base.map = nv50_disp_chan_map, .base.map = nv50_disp_chan_map,
.base.ntfy = nv50_disp_chan_ntfy, .base.ntfy = nv50_disp_chan_ntfy,
.base.rd32 = nv50_disp_chan_rd32, .base.rd32 = nv50_disp_chan_rd32,
...@@ -586,7 +588,7 @@ nv50_disp_mast_ofuncs = { ...@@ -586,7 +588,7 @@ nv50_disp_mast_ofuncs = {
******************************************************************************/ ******************************************************************************/
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nv50_disp_sync_mthd_base = { nv50_disp_base_mthd_base = {
.mthd = 0x0000, .mthd = 0x0000,
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
...@@ -611,7 +613,7 @@ nv50_disp_sync_mthd_base = { ...@@ -611,7 +613,7 @@ nv50_disp_sync_mthd_base = {
}; };
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nv50_disp_sync_mthd_image = { nv50_disp_base_mthd_image = {
.mthd = 0x0400, .mthd = 0x0400,
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
...@@ -625,18 +627,18 @@ nv50_disp_sync_mthd_image = { ...@@ -625,18 +627,18 @@ nv50_disp_sync_mthd_image = {
}; };
static const struct nv50_disp_mthd_chan static const struct nv50_disp_mthd_chan
nv50_disp_sync_mthd_chan = { nv50_disp_base_mthd_chan = {
.name = "Base", .name = "Base",
.addr = 0x000540, .addr = 0x000540,
.data = { .data = {
{ "Global", 1, &nv50_disp_sync_mthd_base }, { "Global", 1, &nv50_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_sync_mthd_image }, { "Image", 2, &nv50_disp_base_mthd_image },
{} {}
} }
}; };
int int
nv50_disp_sync_ctor(struct nouveau_object *parent, nv50_disp_base_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject) struct nouveau_object **pobject)
...@@ -669,8 +671,8 @@ nv50_disp_sync_ctor(struct nouveau_object *parent, ...@@ -669,8 +671,8 @@ nv50_disp_sync_ctor(struct nouveau_object *parent,
} }
struct nv50_disp_chan_impl struct nv50_disp_chan_impl
nv50_disp_sync_ofuncs = { nv50_disp_base_ofuncs = {
.base.ctor = nv50_disp_sync_ctor, .base.ctor = nv50_disp_base_ctor,
.base.dtor = nv50_disp_dmac_dtor, .base.dtor = nv50_disp_dmac_dtor,
.base.init = nv50_disp_dmac_init, .base.init = nv50_disp_dmac_init,
.base.fini = nv50_disp_dmac_fini, .base.fini = nv50_disp_dmac_fini,
...@@ -942,7 +944,7 @@ nv50_disp_curs_ofuncs = { ...@@ -942,7 +944,7 @@ nv50_disp_curs_ofuncs = {
******************************************************************************/ ******************************************************************************/
int int
nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0) nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
{ {
const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540)); const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540)); const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
...@@ -974,7 +976,7 @@ nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0) ...@@ -974,7 +976,7 @@ nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
} }
int int
nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd, nv50_disp_main_mthd(struct nouveau_object *object, u32 mthd,
void *data, u32 size) void *data, u32 size)
{ {
const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
...@@ -1098,7 +1100,7 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd, ...@@ -1098,7 +1100,7 @@ nv50_disp_base_mthd(struct nouveau_object *object, u32 mthd,
} }
int int
nv50_disp_base_ctor(struct nouveau_object *parent, nv50_disp_main_ctor(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject) struct nouveau_object **pobject)
...@@ -1118,7 +1120,7 @@ nv50_disp_base_ctor(struct nouveau_object *parent, ...@@ -1118,7 +1120,7 @@ nv50_disp_base_ctor(struct nouveau_object *parent,
} }
void void
nv50_disp_base_dtor(struct nouveau_object *object) nv50_disp_main_dtor(struct nouveau_object *object)
{ {
struct nv50_disp_base *base = (void *)object; struct nv50_disp_base *base = (void *)object;
nouveau_ramht_ref(NULL, &base->ramht); nouveau_ramht_ref(NULL, &base->ramht);
...@@ -1126,7 +1128,7 @@ nv50_disp_base_dtor(struct nouveau_object *object) ...@@ -1126,7 +1128,7 @@ nv50_disp_base_dtor(struct nouveau_object *object)
} }
static int static int
nv50_disp_base_init(struct nouveau_object *object) nv50_disp_main_init(struct nouveau_object *object)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_base *base = (void *)object; struct nv50_disp_base *base = (void *)object;
...@@ -1194,7 +1196,7 @@ nv50_disp_base_init(struct nouveau_object *object) ...@@ -1194,7 +1196,7 @@ nv50_disp_base_init(struct nouveau_object *object)
} }
static int static int
nv50_disp_base_fini(struct nouveau_object *object, bool suspend) nv50_disp_main_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_base *base = (void *)object; struct nv50_disp_base *base = (void *)object;
...@@ -1207,25 +1209,25 @@ nv50_disp_base_fini(struct nouveau_object *object, bool suspend) ...@@ -1207,25 +1209,25 @@ nv50_disp_base_fini(struct nouveau_object *object, bool suspend)
} }
struct nouveau_ofuncs struct nouveau_ofuncs
nv50_disp_base_ofuncs = { nv50_disp_main_ofuncs = {
.ctor = nv50_disp_base_ctor, .ctor = nv50_disp_main_ctor,
.dtor = nv50_disp_base_dtor, .dtor = nv50_disp_main_dtor,
.init = nv50_disp_base_init, .init = nv50_disp_main_init,
.fini = nv50_disp_base_fini, .fini = nv50_disp_main_fini,
.mthd = nv50_disp_base_mthd, .mthd = nv50_disp_main_mthd,
.ntfy = nouveau_disp_ntfy, .ntfy = nouveau_disp_ntfy,
}; };
static struct nouveau_oclass static struct nouveau_oclass
nv50_disp_base_oclass[] = { nv50_disp_main_oclass[] = {
{ NV50_DISP, &nv50_disp_base_ofuncs }, { NV50_DISP, &nv50_disp_main_ofuncs },
{} {}
}; };
static struct nouveau_oclass static struct nouveau_oclass
nv50_disp_sclass[] = { nv50_disp_sclass[] = {
{ NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
{ NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
{ NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
...@@ -1974,7 +1976,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1974,7 +1976,7 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nv50_disp_base_oclass; nv_engine(priv)->sclass = nv50_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
...@@ -2007,9 +2009,9 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { ...@@ -2007,9 +2009,9 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nv50_disp_vblank_func, .base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass, .base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv50_disp_mast_mthd_chan, .mthd.core = &nv50_disp_core_mthd_chan,
.mthd.base = &nv50_disp_sync_mthd_chan, .mthd.base = &nv50_disp_base_mthd_chan,
.mthd.ovly = &nv50_disp_ovly_mthd_chan, .mthd.ovly = &nv50_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos, .head.scanoutpos = nv50_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -42,6 +42,7 @@ struct nv50_disp_priv { ...@@ -42,6 +42,7 @@ struct nv50_disp_priv {
int (*hda_eld)(NV50_DISP_MTHD_V1); int (*hda_eld)(NV50_DISP_MTHD_V1);
int (*hdmi)(NV50_DISP_MTHD_V1); int (*hdmi)(NV50_DISP_MTHD_V1);
u32 lvdsconf; u32 lvdsconf;
void (*magic)(struct nvkm_output *);
} sor; } sor;
struct { struct {
int nr; int nr;
...@@ -63,10 +64,10 @@ struct nv50_disp_impl { ...@@ -63,10 +64,10 @@ struct nv50_disp_impl {
} head; } head;
}; };
int nv50_disp_base_scanoutpos(NV50_DISP_MTHD_V0); int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
int nv50_disp_base_mthd(struct nouveau_object *, u32, void *, u32); int nv50_disp_main_mthd(struct nouveau_object *, u32, void *, u32);
int nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0); int nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
int nv50_dac_power(NV50_DISP_MTHD_V1); int nv50_dac_power(NV50_DISP_MTHD_V1);
int nv50_dac_sense(NV50_DISP_MTHD_V1); int nv50_dac_sense(NV50_DISP_MTHD_V1);
...@@ -169,18 +170,18 @@ struct nv50_disp_mthd_chan { ...@@ -169,18 +170,18 @@ struct nv50_disp_mthd_chan {
} data[]; } data[];
}; };
extern struct nv50_disp_chan_impl nv50_disp_mast_ofuncs; extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs;
int nv50_disp_mast_ctor(struct nouveau_object *, struct nouveau_object *, int nv50_disp_core_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32, struct nouveau_oclass *, void *, u32,
struct nouveau_object **); struct nouveau_object **);
extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_base; extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base;
extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_sor; extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor;
extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_pior; extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior;
extern struct nv50_disp_chan_impl nv50_disp_sync_ofuncs; extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs;
int nv50_disp_sync_ctor(struct nouveau_object *, struct nouveau_object *, int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32, struct nouveau_oclass *, void *, u32,
struct nouveau_object **); struct nouveau_object **);
extern const struct nv50_disp_mthd_list nv50_disp_sync_mthd_image; extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image;
extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs; extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs;
int nv50_disp_ovly_ctor(struct nouveau_object *, struct nouveau_object *, int nv50_disp_ovly_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32, struct nouveau_oclass *, void *, u32,
...@@ -194,12 +195,12 @@ extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs; ...@@ -194,12 +195,12 @@ extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs;
int nv50_disp_curs_ctor(struct nouveau_object *, struct nouveau_object *, int nv50_disp_curs_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32, struct nouveau_oclass *, void *, u32,
struct nouveau_object **); struct nouveau_object **);
extern struct nouveau_ofuncs nv50_disp_base_ofuncs; extern struct nouveau_ofuncs nv50_disp_main_ofuncs;
int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *, int nv50_disp_main_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32, struct nouveau_oclass *, void *, u32,
struct nouveau_object **); struct nouveau_object **);
void nv50_disp_base_dtor(struct nouveau_object *); void nv50_disp_main_dtor(struct nouveau_object *);
extern struct nouveau_omthds nv50_disp_base_omthds[]; extern struct nouveau_omthds nv50_disp_main_omthds[];
extern struct nouveau_oclass nv50_disp_cclass; extern struct nouveau_oclass nv50_disp_cclass;
void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head, void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
const struct nv50_disp_mthd_chan *); const struct nv50_disp_mthd_chan *);
...@@ -207,31 +208,31 @@ void nv50_disp_intr_supervisor(struct work_struct *); ...@@ -207,31 +208,31 @@ void nv50_disp_intr_supervisor(struct work_struct *);
void nv50_disp_intr(struct nouveau_subdev *); void nv50_disp_intr(struct nouveau_subdev *);
extern const struct nvkm_event_func nv50_disp_vblank_func; extern const struct nvkm_event_func nv50_disp_vblank_func;
extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_chan nv84_disp_core_mthd_chan;
extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac; extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_dac;
extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head; extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_head;
extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan; extern const struct nv50_disp_mthd_chan nv84_disp_base_mthd_chan;
extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan; extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_chan nv94_disp_core_mthd_chan;
extern struct nv50_disp_chan_impl nvd0_disp_mast_ofuncs; extern struct nv50_disp_chan_impl nvd0_disp_core_ofuncs;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_base; extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_base;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_dac; extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_dac;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_sor; extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_sor;
extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_pior; extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_pior;
extern struct nv50_disp_chan_impl nvd0_disp_sync_ofuncs; extern struct nv50_disp_chan_impl nvd0_disp_base_ofuncs;
extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs; extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan; extern const struct nv50_disp_mthd_chan nvd0_disp_base_mthd_chan;
extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs; extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs; extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
extern struct nouveau_ofuncs nvd0_disp_base_ofuncs; extern struct nouveau_ofuncs nvd0_disp_main_ofuncs;
extern struct nouveau_oclass nvd0_disp_cclass; extern struct nouveau_oclass nvd0_disp_cclass;
void nvd0_disp_intr_supervisor(struct work_struct *); void nvd0_disp_intr_supervisor(struct work_struct *);
void nvd0_disp_intr(struct nouveau_subdev *); void nvd0_disp_intr(struct nouveau_subdev *);
extern const struct nvkm_event_func nvd0_disp_vblank_func; extern const struct nvkm_event_func nvd0_disp_vblank_func;
extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_chan nve0_disp_core_mthd_chan;
extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
extern struct nvkm_output_dp_impl nv50_pior_dp_impl; extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
...@@ -242,6 +243,10 @@ int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); ...@@ -242,6 +243,10 @@ int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
extern struct nouveau_oclass *nv94_disp_outp_sclass[]; extern struct nouveau_oclass *nv94_disp_outp_sclass[];
extern struct nvkm_output_dp_impl nvd0_sor_dp_impl; extern struct nvkm_output_dp_impl nvd0_sor_dp_impl;
int nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool);
extern struct nouveau_oclass *nvd0_disp_outp_sclass[]; extern struct nouveau_oclass *nvd0_disp_outp_sclass[];
void gm204_sor_magic(struct nvkm_output *outp);
extern struct nvkm_output_dp_impl gm204_sor_dp_impl;
#endif #endif
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
******************************************************************************/ ******************************************************************************/
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nv84_disp_mast_mthd_dac = { nv84_disp_core_mthd_dac = {
.mthd = 0x0080, .mthd = 0x0080,
.addr = 0x000008, .addr = 0x000008,
.data = { .data = {
...@@ -46,7 +46,7 @@ nv84_disp_mast_mthd_dac = { ...@@ -46,7 +46,7 @@ nv84_disp_mast_mthd_dac = {
}; };
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nv84_disp_mast_mthd_head = { nv84_disp_core_mthd_head = {
.mthd = 0x0400, .mthd = 0x0400,
.addr = 0x000540, .addr = 0x000540,
.data = { .data = {
...@@ -98,15 +98,15 @@ nv84_disp_mast_mthd_head = { ...@@ -98,15 +98,15 @@ nv84_disp_mast_mthd_head = {
}; };
const struct nv50_disp_mthd_chan const struct nv50_disp_mthd_chan
nv84_disp_mast_mthd_chan = { nv84_disp_core_mthd_chan = {
.name = "Core", .name = "Core",
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
{ "Global", 1, &nv50_disp_mast_mthd_base }, { "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &nv84_disp_mast_mthd_dac }, { "DAC", 3, &nv84_disp_core_mthd_dac },
{ "SOR", 2, &nv50_disp_mast_mthd_sor }, { "SOR", 2, &nv50_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_mast_mthd_pior }, { "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &nv84_disp_mast_mthd_head }, { "HEAD", 2, &nv84_disp_core_mthd_head },
{} {}
} }
}; };
...@@ -116,7 +116,7 @@ nv84_disp_mast_mthd_chan = { ...@@ -116,7 +116,7 @@ nv84_disp_mast_mthd_chan = {
******************************************************************************/ ******************************************************************************/
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nv84_disp_sync_mthd_base = { nv84_disp_base_mthd_base = {
.mthd = 0x0000, .mthd = 0x0000,
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
...@@ -146,12 +146,12 @@ nv84_disp_sync_mthd_base = { ...@@ -146,12 +146,12 @@ nv84_disp_sync_mthd_base = {
}; };
const struct nv50_disp_mthd_chan const struct nv50_disp_mthd_chan
nv84_disp_sync_mthd_chan = { nv84_disp_base_mthd_chan = {
.name = "Base", .name = "Base",
.addr = 0x000540, .addr = 0x000540,
.data = { .data = {
{ "Global", 1, &nv84_disp_sync_mthd_base }, { "Global", 1, &nv84_disp_base_mthd_base },
{ "Image", 2, &nv50_disp_sync_mthd_image }, { "Image", 2, &nv50_disp_base_mthd_image },
{} {}
} }
}; };
...@@ -204,8 +204,8 @@ nv84_disp_ovly_mthd_chan = { ...@@ -204,8 +204,8 @@ nv84_disp_ovly_mthd_chan = {
static struct nouveau_oclass static struct nouveau_oclass
nv84_disp_sclass[] = { nv84_disp_sclass[] = {
{ G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
{ G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
{ G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
...@@ -213,8 +213,8 @@ nv84_disp_sclass[] = { ...@@ -213,8 +213,8 @@ nv84_disp_sclass[] = {
}; };
static struct nouveau_oclass static struct nouveau_oclass
nv84_disp_base_oclass[] = { nv84_disp_main_oclass[] = {
{ G82_DISP, &nv50_disp_base_ofuncs }, { G82_DISP, &nv50_disp_main_ofuncs },
{} {}
}; };
...@@ -240,7 +240,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -240,7 +240,7 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nv84_disp_base_oclass; nv_engine(priv)->sclass = nv84_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
...@@ -268,9 +268,9 @@ nv84_disp_oclass = &(struct nv50_disp_impl) { ...@@ -268,9 +268,9 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nv50_disp_vblank_func, .base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass, .base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan, .mthd.core = &nv84_disp_core_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_base_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos, .head.scanoutpos = nv50_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
******************************************************************************/ ******************************************************************************/
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nv94_disp_mast_mthd_sor = { nv94_disp_core_mthd_sor = {
.mthd = 0x0040, .mthd = 0x0040,
.addr = 0x000008, .addr = 0x000008,
.data = { .data = {
...@@ -44,15 +44,15 @@ nv94_disp_mast_mthd_sor = { ...@@ -44,15 +44,15 @@ nv94_disp_mast_mthd_sor = {
}; };
const struct nv50_disp_mthd_chan const struct nv50_disp_mthd_chan
nv94_disp_mast_mthd_chan = { nv94_disp_core_mthd_chan = {
.name = "Core", .name = "Core",
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
{ "Global", 1, &nv50_disp_mast_mthd_base }, { "Global", 1, &nv50_disp_core_mthd_base },
{ "DAC", 3, &nv84_disp_mast_mthd_dac }, { "DAC", 3, &nv84_disp_core_mthd_dac },
{ "SOR", 4, &nv94_disp_mast_mthd_sor }, { "SOR", 4, &nv94_disp_core_mthd_sor },
{ "PIOR", 3, &nv50_disp_mast_mthd_pior }, { "PIOR", 3, &nv50_disp_core_mthd_pior },
{ "HEAD", 2, &nv84_disp_mast_mthd_head }, { "HEAD", 2, &nv84_disp_core_mthd_head },
{} {}
} }
}; };
...@@ -63,8 +63,8 @@ nv94_disp_mast_mthd_chan = { ...@@ -63,8 +63,8 @@ nv94_disp_mast_mthd_chan = {
static struct nouveau_oclass static struct nouveau_oclass
nv94_disp_sclass[] = { nv94_disp_sclass[] = {
{ GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
...@@ -72,8 +72,8 @@ nv94_disp_sclass[] = { ...@@ -72,8 +72,8 @@ nv94_disp_sclass[] = {
}; };
static struct nouveau_oclass static struct nouveau_oclass
nv94_disp_base_oclass[] = { nv94_disp_main_oclass[] = {
{ GT206_DISP, &nv50_disp_base_ofuncs }, { GT206_DISP, &nv50_disp_main_ofuncs },
{} {}
}; };
...@@ -99,7 +99,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -99,7 +99,7 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nv94_disp_base_oclass; nv_engine(priv)->sclass = nv94_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
...@@ -134,9 +134,9 @@ nv94_disp_oclass = &(struct nv50_disp_impl) { ...@@ -134,9 +134,9 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nv50_disp_vblank_func, .base.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass, .base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan, .mthd.core = &nv94_disp_core_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_base_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos, .head.scanoutpos = nv50_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -80,8 +80,8 @@ nva0_disp_ovly_mthd_chan = { ...@@ -80,8 +80,8 @@ nva0_disp_ovly_mthd_chan = {
static struct nouveau_oclass static struct nouveau_oclass
nva0_disp_sclass[] = { nva0_disp_sclass[] = {
{ GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
{ GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
{ GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
...@@ -89,8 +89,8 @@ nva0_disp_sclass[] = { ...@@ -89,8 +89,8 @@ nva0_disp_sclass[] = {
}; };
static struct nouveau_oclass static struct nouveau_oclass
nva0_disp_base_oclass[] = { nva0_disp_main_oclass[] = {
{ GT200_DISP, &nv50_disp_base_ofuncs }, { GT200_DISP, &nv50_disp_main_ofuncs },
{} {}
}; };
...@@ -116,7 +116,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -116,7 +116,7 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nva0_disp_base_oclass; nv_engine(priv)->sclass = nva0_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
...@@ -144,9 +144,9 @@ nva0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -144,9 +144,9 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nv50_disp_vblank_func, .base.vblank = &nv50_disp_vblank_func,
.base.outp = nv50_disp_outp_sclass, .base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan, .mthd.core = &nv84_disp_core_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_base_mthd_chan,
.mthd.ovly = &nva0_disp_ovly_mthd_chan, .mthd.ovly = &nva0_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos, .head.scanoutpos = nv50_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
static struct nouveau_oclass static struct nouveau_oclass
nva3_disp_sclass[] = { nva3_disp_sclass[] = {
{ GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_mast_ofuncs.base }, { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
{ GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_sync_ofuncs.base }, { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
{ GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
{ GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
{ GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
...@@ -44,8 +44,8 @@ nva3_disp_sclass[] = { ...@@ -44,8 +44,8 @@ nva3_disp_sclass[] = {
}; };
static struct nouveau_oclass static struct nouveau_oclass
nva3_disp_base_oclass[] = { nva3_disp_main_oclass[] = {
{ GT214_DISP, &nv50_disp_base_ofuncs }, { GT214_DISP, &nv50_disp_main_ofuncs },
{} {}
}; };
...@@ -71,7 +71,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -71,7 +71,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nva3_disp_base_oclass; nv_engine(priv)->sclass = nva3_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr; nv_subdev(priv)->intr = nv50_disp_intr;
INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
...@@ -100,9 +100,9 @@ nva3_disp_oclass = &(struct nv50_disp_impl) { ...@@ -100,9 +100,9 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nv50_disp_vblank_func, .base.vblank = &nv50_disp_vblank_func,
.base.outp = nv94_disp_outp_sclass, .base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan, .mthd.core = &nv94_disp_core_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_base_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
.mthd.prev = 0x000004, .mthd.prev = 0x000004,
.head.scanoutpos = nv50_disp_base_scanoutpos, .head.scanoutpos = nv50_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -51,12 +51,14 @@ nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) ...@@ -51,12 +51,14 @@ nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{ {
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index); nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
nv_wr32(priv, 0x61008c, 0x00000001 << index);
} }
static void static void
nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{ {
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_wr32(priv, 0x61008c, 0x00000001 << index);
nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index); nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
} }
...@@ -151,7 +153,7 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend) ...@@ -151,7 +153,7 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
******************************************************************************/ ******************************************************************************/
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nvd0_disp_mast_mthd_base = { nvd0_disp_core_mthd_base = {
.mthd = 0x0000, .mthd = 0x0000,
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
...@@ -164,7 +166,7 @@ nvd0_disp_mast_mthd_base = { ...@@ -164,7 +166,7 @@ nvd0_disp_mast_mthd_base = {
}; };
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nvd0_disp_mast_mthd_dac = { nvd0_disp_core_mthd_dac = {
.mthd = 0x0020, .mthd = 0x0020,
.addr = 0x000020, .addr = 0x000020,
.data = { .data = {
...@@ -177,7 +179,7 @@ nvd0_disp_mast_mthd_dac = { ...@@ -177,7 +179,7 @@ nvd0_disp_mast_mthd_dac = {
}; };
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nvd0_disp_mast_mthd_sor = { nvd0_disp_core_mthd_sor = {
.mthd = 0x0020, .mthd = 0x0020,
.addr = 0x000020, .addr = 0x000020,
.data = { .data = {
...@@ -190,7 +192,7 @@ nvd0_disp_mast_mthd_sor = { ...@@ -190,7 +192,7 @@ nvd0_disp_mast_mthd_sor = {
}; };
const struct nv50_disp_mthd_list const struct nv50_disp_mthd_list
nvd0_disp_mast_mthd_pior = { nvd0_disp_core_mthd_pior = {
.mthd = 0x0020, .mthd = 0x0020,
.addr = 0x000020, .addr = 0x000020,
.data = { .data = {
...@@ -203,7 +205,7 @@ nvd0_disp_mast_mthd_pior = { ...@@ -203,7 +205,7 @@ nvd0_disp_mast_mthd_pior = {
}; };
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nvd0_disp_mast_mthd_head = { nvd0_disp_core_mthd_head = {
.mthd = 0x0300, .mthd = 0x0300,
.addr = 0x000300, .addr = 0x000300,
.data = { .data = {
...@@ -277,21 +279,21 @@ nvd0_disp_mast_mthd_head = { ...@@ -277,21 +279,21 @@ nvd0_disp_mast_mthd_head = {
}; };
static const struct nv50_disp_mthd_chan static const struct nv50_disp_mthd_chan
nvd0_disp_mast_mthd_chan = { nvd0_disp_core_mthd_chan = {
.name = "Core", .name = "Core",
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
{ "Global", 1, &nvd0_disp_mast_mthd_base }, { "Global", 1, &nvd0_disp_core_mthd_base },
{ "DAC", 3, &nvd0_disp_mast_mthd_dac }, { "DAC", 3, &nvd0_disp_core_mthd_dac },
{ "SOR", 8, &nvd0_disp_mast_mthd_sor }, { "SOR", 8, &nvd0_disp_core_mthd_sor },
{ "PIOR", 4, &nvd0_disp_mast_mthd_pior }, { "PIOR", 4, &nvd0_disp_core_mthd_pior },
{ "HEAD", 4, &nvd0_disp_mast_mthd_head }, { "HEAD", 4, &nvd0_disp_core_mthd_head },
{} {}
} }
}; };
static int static int
nvd0_disp_mast_init(struct nouveau_object *object) nvd0_disp_core_init(struct nouveau_object *object)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_dmac *mast = (void *)object; struct nv50_disp_dmac *mast = (void *)object;
...@@ -322,7 +324,7 @@ nvd0_disp_mast_init(struct nouveau_object *object) ...@@ -322,7 +324,7 @@ nvd0_disp_mast_init(struct nouveau_object *object)
} }
static int static int
nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend) nvd0_disp_core_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_dmac *mast = (void *)object; struct nv50_disp_dmac *mast = (void *)object;
...@@ -344,11 +346,11 @@ nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend) ...@@ -344,11 +346,11 @@ nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
} }
struct nv50_disp_chan_impl struct nv50_disp_chan_impl
nvd0_disp_mast_ofuncs = { nvd0_disp_core_ofuncs = {
.base.ctor = nv50_disp_mast_ctor, .base.ctor = nv50_disp_core_ctor,
.base.dtor = nv50_disp_dmac_dtor, .base.dtor = nv50_disp_dmac_dtor,
.base.init = nvd0_disp_mast_init, .base.init = nvd0_disp_core_init,
.base.fini = nvd0_disp_mast_fini, .base.fini = nvd0_disp_core_fini,
.base.ntfy = nv50_disp_chan_ntfy, .base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map, .base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32, .base.rd32 = nv50_disp_chan_rd32,
...@@ -363,7 +365,7 @@ nvd0_disp_mast_ofuncs = { ...@@ -363,7 +365,7 @@ nvd0_disp_mast_ofuncs = {
******************************************************************************/ ******************************************************************************/
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nvd0_disp_sync_mthd_base = { nvd0_disp_base_mthd_base = {
.mthd = 0x0000, .mthd = 0x0000,
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
...@@ -413,7 +415,7 @@ nvd0_disp_sync_mthd_base = { ...@@ -413,7 +415,7 @@ nvd0_disp_sync_mthd_base = {
}; };
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nvd0_disp_sync_mthd_image = { nvd0_disp_base_mthd_image = {
.mthd = 0x0400, .mthd = 0x0400,
.addr = 0x000400, .addr = 0x000400,
.data = { .data = {
...@@ -427,19 +429,19 @@ nvd0_disp_sync_mthd_image = { ...@@ -427,19 +429,19 @@ nvd0_disp_sync_mthd_image = {
}; };
const struct nv50_disp_mthd_chan const struct nv50_disp_mthd_chan
nvd0_disp_sync_mthd_chan = { nvd0_disp_base_mthd_chan = {
.name = "Base", .name = "Base",
.addr = 0x001000, .addr = 0x001000,
.data = { .data = {
{ "Global", 1, &nvd0_disp_sync_mthd_base }, { "Global", 1, &nvd0_disp_base_mthd_base },
{ "Image", 2, &nvd0_disp_sync_mthd_image }, { "Image", 2, &nvd0_disp_base_mthd_image },
{} {}
} }
}; };
struct nv50_disp_chan_impl struct nv50_disp_chan_impl
nvd0_disp_sync_ofuncs = { nvd0_disp_base_ofuncs = {
.base.ctor = nv50_disp_sync_ctor, .base.ctor = nv50_disp_base_ctor,
.base.dtor = nv50_disp_dmac_dtor, .base.dtor = nv50_disp_dmac_dtor,
.base.init = nvd0_disp_dmac_init, .base.init = nvd0_disp_dmac_init,
.base.fini = nvd0_disp_dmac_fini, .base.fini = nvd0_disp_dmac_fini,
...@@ -624,7 +626,7 @@ nvd0_disp_curs_ofuncs = { ...@@ -624,7 +626,7 @@ nvd0_disp_curs_ofuncs = {
******************************************************************************/ ******************************************************************************/
int int
nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0) nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
{ {
const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300)); const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300));
const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300)); const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
...@@ -656,7 +658,7 @@ nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0) ...@@ -656,7 +658,7 @@ nvd0_disp_base_scanoutpos(NV50_DISP_MTHD_V0)
} }
static int static int
nvd0_disp_base_init(struct nouveau_object *object) nvd0_disp_main_init(struct nouveau_object *object)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_base *base = (void *)object; struct nv50_disp_base *base = (void *)object;
...@@ -725,7 +727,7 @@ nvd0_disp_base_init(struct nouveau_object *object) ...@@ -725,7 +727,7 @@ nvd0_disp_base_init(struct nouveau_object *object)
} }
static int static int
nvd0_disp_base_fini(struct nouveau_object *object, bool suspend) nvd0_disp_main_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
struct nv50_disp_base *base = (void *)object; struct nv50_disp_base *base = (void *)object;
...@@ -737,25 +739,25 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend) ...@@ -737,25 +739,25 @@ nvd0_disp_base_fini(struct nouveau_object *object, bool suspend)
} }
struct nouveau_ofuncs struct nouveau_ofuncs
nvd0_disp_base_ofuncs = { nvd0_disp_main_ofuncs = {
.ctor = nv50_disp_base_ctor, .ctor = nv50_disp_main_ctor,
.dtor = nv50_disp_base_dtor, .dtor = nv50_disp_main_dtor,
.init = nvd0_disp_base_init, .init = nvd0_disp_main_init,
.fini = nvd0_disp_base_fini, .fini = nvd0_disp_main_fini,
.mthd = nv50_disp_base_mthd, .mthd = nv50_disp_main_mthd,
.ntfy = nouveau_disp_ntfy, .ntfy = nouveau_disp_ntfy,
}; };
static struct nouveau_oclass static struct nouveau_oclass
nvd0_disp_base_oclass[] = { nvd0_disp_main_oclass[] = {
{ GF110_DISP, &nvd0_disp_base_ofuncs }, { GF110_DISP, &nvd0_disp_main_ofuncs },
{} {}
}; };
static struct nouveau_oclass static struct nouveau_oclass
nvd0_disp_sclass[] = { nvd0_disp_sclass[] = {
{ GF110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, { GF110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
{ GF110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, { GF110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
{ GF110_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, { GF110_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GF110_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, { GF110_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GF110_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, { GF110_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
...@@ -1055,6 +1057,9 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) ...@@ -1055,6 +1057,9 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
if (nvkm_output_dp_train(outp, pclk, true)) if (nvkm_output_dp_train(outp, pclk, true))
ERR("link not trained before attach\n"); ERR("link not trained before attach\n");
} else {
if (priv->sor.magic)
priv->sor.magic(outp);
} }
exec_clkcmp(priv, head, 0, pclk, &conf); exec_clkcmp(priv, head, 0, pclk, &conf);
...@@ -1063,10 +1068,18 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) ...@@ -1063,10 +1068,18 @@ nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
data = 0x00000000; data = 0x00000000;
} else { } else {
if (outp->info.type == DCB_OUTPUT_DP)
nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info);
addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
data = (conf & 0x0100) ? 0x00000101 : 0x00000000; data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
switch (outp->info.type) {
case DCB_OUTPUT_TMDS:
nv_mask(priv, addr, 0x007c0000, 0x00280000);
break;
case DCB_OUTPUT_DP:
nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info);
break;
default:
break;
}
} }
nv_mask(priv, addr, 0x00000707, data); nv_mask(priv, addr, 0x00000707, data);
...@@ -1259,7 +1272,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1259,7 +1272,7 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nvd0_disp_base_oclass; nv_engine(priv)->sclass = nvd0_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr; nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
...@@ -1292,9 +1305,9 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -1292,9 +1305,9 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nvd0_disp_vblank_func, .base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nvd0_disp_mast_mthd_chan, .mthd.core = &nvd0_disp_core_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_base_mthd_chan,
.mthd.ovly = &nvd0_disp_ovly_mthd_chan, .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos, .head.scanoutpos = nvd0_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
******************************************************************************/ ******************************************************************************/
static const struct nv50_disp_mthd_list static const struct nv50_disp_mthd_list
nve0_disp_mast_mthd_head = { nve0_disp_core_mthd_head = {
.mthd = 0x0300, .mthd = 0x0300,
.addr = 0x000300, .addr = 0x000300,
.data = { .data = {
...@@ -113,15 +113,15 @@ nve0_disp_mast_mthd_head = { ...@@ -113,15 +113,15 @@ nve0_disp_mast_mthd_head = {
}; };
const struct nv50_disp_mthd_chan const struct nv50_disp_mthd_chan
nve0_disp_mast_mthd_chan = { nve0_disp_core_mthd_chan = {
.name = "Core", .name = "Core",
.addr = 0x000000, .addr = 0x000000,
.data = { .data = {
{ "Global", 1, &nvd0_disp_mast_mthd_base }, { "Global", 1, &nvd0_disp_core_mthd_base },
{ "DAC", 3, &nvd0_disp_mast_mthd_dac }, { "DAC", 3, &nvd0_disp_core_mthd_dac },
{ "SOR", 8, &nvd0_disp_mast_mthd_sor }, { "SOR", 8, &nvd0_disp_core_mthd_sor },
{ "PIOR", 4, &nvd0_disp_mast_mthd_pior }, { "PIOR", 4, &nvd0_disp_core_mthd_pior },
{ "HEAD", 4, &nve0_disp_mast_mthd_head }, { "HEAD", 4, &nve0_disp_core_mthd_head },
{} {}
} }
}; };
...@@ -200,8 +200,8 @@ nve0_disp_ovly_mthd_chan = { ...@@ -200,8 +200,8 @@ nve0_disp_ovly_mthd_chan = {
static struct nouveau_oclass static struct nouveau_oclass
nve0_disp_sclass[] = { nve0_disp_sclass[] = {
{ GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, { GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
{ GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, { GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
...@@ -209,8 +209,8 @@ nve0_disp_sclass[] = { ...@@ -209,8 +209,8 @@ nve0_disp_sclass[] = {
}; };
static struct nouveau_oclass static struct nouveau_oclass
nve0_disp_base_oclass[] = { nve0_disp_main_oclass[] = {
{ GK104_DISP, &nvd0_disp_base_ofuncs }, { GK104_DISP, &nvd0_disp_main_ofuncs },
{} {}
}; };
...@@ -237,7 +237,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -237,7 +237,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nve0_disp_base_oclass; nv_engine(priv)->sclass = nve0_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr; nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
...@@ -264,9 +264,9 @@ nve0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -264,9 +264,9 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nvd0_disp_vblank_func, .base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_core_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_base_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos, .head.scanoutpos = nvd0_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
static struct nouveau_oclass static struct nouveau_oclass
nvf0_disp_sclass[] = { nvf0_disp_sclass[] = {
{ GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_mast_ofuncs.base }, { GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
{ GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_sync_ofuncs.base }, { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
{ GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base }, { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
{ GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base }, { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
{ GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base }, { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
...@@ -44,8 +44,8 @@ nvf0_disp_sclass[] = { ...@@ -44,8 +44,8 @@ nvf0_disp_sclass[] = {
}; };
static struct nouveau_oclass static struct nouveau_oclass
nvf0_disp_base_oclass[] = { nvf0_disp_main_oclass[] = {
{ GK110_DISP, &nvd0_disp_base_ofuncs }, { GK110_DISP, &nvd0_disp_main_ofuncs },
{} {}
}; };
...@@ -72,7 +72,7 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -72,7 +72,7 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret) if (ret)
return ret; return ret;
nv_engine(priv)->sclass = nvf0_disp_base_oclass; nv_engine(priv)->sclass = nvf0_disp_main_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass; nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr; nv_subdev(priv)->intr = nvd0_disp_intr;
INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
...@@ -99,9 +99,9 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -99,9 +99,9 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
}, },
.base.vblank = &nvd0_disp_vblank_func, .base.vblank = &nvd0_disp_vblank_func,
.base.outp = nvd0_disp_outp_sclass, .base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_core_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_base_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
.mthd.prev = -0x020000, .mthd.prev = -0x020000,
.head.scanoutpos = nvd0_disp_base_scanoutpos, .head.scanoutpos = nvd0_disp_main_scanoutpos,
}.base.base; }.base.base;
...@@ -85,7 +85,10 @@ nvkm_output_create_(struct nouveau_object *parent, ...@@ -85,7 +85,10 @@ nvkm_output_create_(struct nouveau_object *parent,
dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index, dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
dcbE->bus, dcbE->heads); dcbE->bus, dcbE->heads);
outp->port = i2c->find(i2c, outp->info.i2c_index); if (outp->info.type != DCB_OUTPUT_DP)
outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index));
else
outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index));
outp->edid = outp->port; outp->edid = outp->port;
data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
......
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <core/os.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/dp.h>
#include <subdev/bios/init.h>
#include <subdev/timer.h>
#include "nv50.h"
static inline u32
gm204_sor_soff(struct nvkm_output_dp *outp)
{
return (ffs(outp->base.info.or) - 1) * 0x800;
}
static inline u32
gm204_sor_loff(struct nvkm_output_dp *outp)
{
return gm204_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
}
void
gm204_sor_magic(struct nvkm_output *outp)
{
struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 soff = outp->or * 0x100;
const u32 data = outp->or + 1;
if (outp->info.sorconf.link & 1)
nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data);
if (outp->info.sorconf.link & 2)
nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data);
}
static inline u32
gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
{
return lane * 0x08;
}
static int
gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
{
struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 soff = gm204_sor_soff(outp);
const u32 data = 0x01010101 * pattern;
if (outp->base.info.sorconf.link & 1)
nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data);
else
nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data);
return 0;
}
static int
gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
{
struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 soff = gm204_sor_soff(outp);
const u32 loff = gm204_sor_loff(outp);
u32 mask = 0, i;
for (i = 0; i < nr; i++)
mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3);
nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
return 0;
}
static int
gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
{
struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
struct nouveau_bios *bios = nouveau_bios(priv);
const u32 shift = gm204_sor_dp_lane_map(priv, ln);
const u32 loff = gm204_sor_loff(outp);
u32 addr, data[4];
u8 ver, hdr, cnt, len;
struct nvbios_dpout info;
struct nvbios_dpcfg ocfg;
addr = nvbios_dpout_match(bios, outp->base.info.hasht,
outp->base.info.hashm,
&ver, &hdr, &cnt, &len, &info);
if (!addr)
return -ENODEV;
addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
&ver, &hdr, &cnt, &len, &ocfg);
if (!addr)
return -EINVAL;
data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
data[2] = nv_rd32(priv, 0x61c130 + loff);
if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
return 0;
}
struct nvkm_output_dp_impl
gm204_sor_dp_impl = {
.base.base.handle = DCB_OUTPUT_DP,
.base.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nvkm_output_dp_ctor,
.dtor = _nvkm_output_dp_dtor,
.init = _nvkm_output_dp_init,
.fini = _nvkm_output_dp_fini,
},
.pattern = gm204_sor_dp_pattern,
.lnk_pwr = gm204_sor_dp_lnk_pwr,
.lnk_ctl = nvd0_sor_dp_lnk_ctl,
.drv_ctl = gm204_sor_dp_drv_ctl,
};
...@@ -60,7 +60,7 @@ nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) ...@@ -60,7 +60,7 @@ nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
return 0; return 0;
} }
static int int
nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
{ {
struct nv50_disp_priv *priv = (void *)nouveau_disp(outp); struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
......
...@@ -51,6 +51,7 @@ nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj, ...@@ -51,6 +51,7 @@ nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
case GK104_DISP_CORE_CHANNEL_DMA: case GK104_DISP_CORE_CHANNEL_DMA:
case GK110_DISP_CORE_CHANNEL_DMA: case GK110_DISP_CORE_CHANNEL_DMA:
case GM107_DISP_CORE_CHANNEL_DMA: case GM107_DISP_CORE_CHANNEL_DMA:
case GM204_DISP_CORE_CHANNEL_DMA:
case GF110_DISP_BASE_CHANNEL_DMA: case GF110_DISP_BASE_CHANNEL_DMA:
case GK104_DISP_BASE_CHANNEL_DMA: case GK104_DISP_BASE_CHANNEL_DMA:
case GK110_DISP_BASE_CHANNEL_DMA: case GK110_DISP_BASE_CHANNEL_DMA:
......
...@@ -792,7 +792,7 @@ nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit) ...@@ -792,7 +792,7 @@ nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit)
nouveau_engctx_put(engctx); nouveau_engctx_put(engctx);
} }
static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = { static const struct nouveau_bitfield nve0_fifo_pbdma_intr_0[] = {
{ 0x00000001, "MEMREQ" }, { 0x00000001, "MEMREQ" },
{ 0x00000002, "MEMACK_TIMEOUT" }, { 0x00000002, "MEMACK_TIMEOUT" },
{ 0x00000004, "MEMACK_EXTRA" }, { 0x00000004, "MEMACK_EXTRA" },
...@@ -827,9 +827,10 @@ static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = { ...@@ -827,9 +827,10 @@ static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = {
}; };
static void static void
nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit) nve0_fifo_intr_pbdma_0(struct nve0_fifo_priv *priv, int unit)
{ {
u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000));
u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask;
u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000)); u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff; u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
...@@ -840,11 +841,12 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit) ...@@ -840,11 +841,12 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
if (stat & 0x00800000) { if (stat & 0x00800000) {
if (!nve0_fifo_swmthd(priv, chid, mthd, data)) if (!nve0_fifo_swmthd(priv, chid, mthd, data))
show &= ~0x00800000; show &= ~0x00800000;
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
} }
if (show) { if (show) {
nv_error(priv, "PBDMA%d:", unit); nv_error(priv, "PBDMA%d:", unit);
nouveau_bitfield_print(nve0_fifo_pbdma_intr, show); nouveau_bitfield_print(nve0_fifo_pbdma_intr_0, show);
pr_cont("\n"); pr_cont("\n");
nv_error(priv, nv_error(priv,
"PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
...@@ -853,10 +855,37 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit) ...@@ -853,10 +855,37 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
subc, mthd, data); subc, mthd, data);
} }
nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
} }
static const struct nouveau_bitfield nve0_fifo_pbdma_intr_1[] = {
{ 0x00000001, "HCE_RE_ILLEGAL_OP" },
{ 0x00000002, "HCE_RE_ALIGNB" },
{ 0x00000004, "HCE_PRIV" },
{ 0x00000008, "HCE_ILLEGAL_MTHD" },
{ 0x00000010, "HCE_ILLEGAL_CLASS" },
{}
};
static void
nve0_fifo_intr_pbdma_1(struct nve0_fifo_priv *priv, int unit)
{
u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000));
u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask;
u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
if (stat) {
nv_error(priv, "PBDMA%d:", unit);
nouveau_bitfield_print(nve0_fifo_pbdma_intr_1, stat);
pr_cont("\n");
nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
nv_rd32(priv, 0x040150 + (unit * 0x2000)),
nv_rd32(priv, 0x040154 + (unit * 0x2000)));
}
nv_wr32(priv, 0x040148 + (unit * 0x2000), stat);
}
static void static void
nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv) nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
{ {
...@@ -939,7 +968,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) ...@@ -939,7 +968,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
u32 mask = nv_rd32(priv, 0x0025a0); u32 mask = nv_rd32(priv, 0x0025a0);
while (mask) { while (mask) {
u32 unit = __ffs(mask); u32 unit = __ffs(mask);
nve0_fifo_intr_pbdma(priv, unit); nve0_fifo_intr_pbdma_0(priv, unit);
nve0_fifo_intr_pbdma_1(priv, unit);
nv_wr32(priv, 0x0025a0, (1 << unit)); nv_wr32(priv, 0x0025a0, (1 << unit));
mask &= ~(1 << unit); mask &= ~(1 << unit);
} }
...@@ -1022,6 +1052,12 @@ nve0_fifo_init(struct nouveau_object *object) ...@@ -1022,6 +1052,12 @@ nve0_fifo_init(struct nouveau_object *object)
nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
} }
/* PBDMA[n].HCE */
for (i = 0; i < priv->spoon_nr; i++) {
nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
}
nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
nv_wr32(priv, 0x002100, 0xffffffff); nv_wr32(priv, 0x002100, 0xffffffff);
......
...@@ -1557,7 +1557,7 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1557,7 +1557,7 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) || nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) || nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad)) nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
return -EINVAL; return -ENODEV;
priv->firmware = true; priv->firmware = true;
} }
......
...@@ -16,6 +16,7 @@ enum nv_subdev_type { ...@@ -16,6 +16,7 @@ enum nv_subdev_type {
* to during POST. * to during POST.
*/ */
NVDEV_SUBDEV_DEVINIT, NVDEV_SUBDEV_DEVINIT,
NVDEV_SUBDEV_IBUS,
NVDEV_SUBDEV_GPIO, NVDEV_SUBDEV_GPIO,
NVDEV_SUBDEV_I2C, NVDEV_SUBDEV_I2C,
NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C, NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
...@@ -31,7 +32,6 @@ enum nv_subdev_type { ...@@ -31,7 +32,6 @@ enum nv_subdev_type {
NVDEV_SUBDEV_TIMER, NVDEV_SUBDEV_TIMER,
NVDEV_SUBDEV_FB, NVDEV_SUBDEV_FB,
NVDEV_SUBDEV_LTC, NVDEV_SUBDEV_LTC,
NVDEV_SUBDEV_IBUS,
NVDEV_SUBDEV_INSTMEM, NVDEV_SUBDEV_INSTMEM,
NVDEV_SUBDEV_VM, NVDEV_SUBDEV_VM,
NVDEV_SUBDEV_BAR, NVDEV_SUBDEV_BAR,
...@@ -92,6 +92,7 @@ struct nouveau_device { ...@@ -92,6 +92,7 @@ struct nouveau_device {
GM100 = 0x110, GM100 = 0x110,
} card_type; } card_type;
u32 chipset; u32 chipset;
u8 chiprev;
u32 crystal; u32 crystal;
struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR]; struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR];
...@@ -158,6 +159,12 @@ nv_device_is_pci(struct nouveau_device *device) ...@@ -158,6 +159,12 @@ nv_device_is_pci(struct nouveau_device *device)
return device->pdev != NULL; return device->pdev != NULL;
} }
static inline bool
nv_device_is_cpu_coherent(struct nouveau_device *device)
{
return (!IS_ENABLED(CONFIG_ARM) && nv_device_is_pci(device));
}
static inline struct device * static inline struct device *
nv_device_base(struct nouveau_device *device) nv_device_base(struct nouveau_device *device)
{ {
......
...@@ -23,11 +23,6 @@ void nouveau_handle_destroy(struct nouveau_handle *); ...@@ -23,11 +23,6 @@ void nouveau_handle_destroy(struct nouveau_handle *);
int nouveau_handle_init(struct nouveau_handle *); int nouveau_handle_init(struct nouveau_handle *);
int nouveau_handle_fini(struct nouveau_handle *, bool suspend); int nouveau_handle_fini(struct nouveau_handle *, bool suspend);
int nouveau_handle_new(struct nouveau_object *, u32 parent, u32 handle,
u16 oclass, void *data, u32 size,
struct nouveau_object **);
int nouveau_handle_del(struct nouveau_object *, u32 parent, u32 handle);
struct nouveau_object * struct nouveau_object *
nouveau_handle_ref(struct nouveau_object *, u32 name); nouveau_handle_ref(struct nouveau_object *, u32 name);
......
...@@ -203,21 +203,4 @@ nv_memcmp(void *obj, u32 addr, const char *str, u32 len) ...@@ -203,21 +203,4 @@ nv_memcmp(void *obj, u32 addr, const char *str, u32 len)
return 0; return 0;
} }
#include <core/handle.h>
static inline int
nouveau_object_new(struct nouveau_object *client, u32 parent, u32 handle,
u16 oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
return nouveau_handle_new(client, parent, handle, oclass,
data, size, pobject);
}
static inline int
nouveau_object_del(struct nouveau_object *client, u32 parent, u32 handle)
{
return nouveau_handle_del(client, parent, handle);
}
#endif #endif
...@@ -31,5 +31,6 @@ extern struct nouveau_oclass *nvd0_disp_oclass; ...@@ -31,5 +31,6 @@ extern struct nouveau_oclass *nvd0_disp_oclass;
extern struct nouveau_oclass *nve0_disp_oclass; extern struct nouveau_oclass *nve0_disp_oclass;
extern struct nouveau_oclass *nvf0_disp_oclass; extern struct nouveau_oclass *nvf0_disp_oclass;
extern struct nouveau_oclass *gm107_disp_oclass; extern struct nouveau_oclass *gm107_disp_oclass;
extern struct nouveau_oclass *gm204_disp_oclass;
#endif #endif
#ifndef __NVBIOS_M0203_H__
#define __NVBIOS_M0203_H__
struct nvbios_M0203T {
#define M0203T_TYPE_RAMCFG 0x00
u8 type;
u16 pointer;
};
u32 nvbios_M0203Te(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u32 nvbios_M0203Tp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_M0203T *);
struct nvbios_M0203E {
#define M0203E_TYPE_DDR2 0x0
#define M0203E_TYPE_DDR3 0x1
#define M0203E_TYPE_GDDR3 0x2
#define M0203E_TYPE_GDDR5 0x3
#define M0203E_TYPE_SKIP 0xf
u8 type;
u8 strap;
u8 group;
};
u32 nvbios_M0203Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
u32 nvbios_M0203Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
struct nvbios_M0203E *);
u32 nvbios_M0203Em(struct nouveau_bios *, u8 ramcfg, u8 *ver, u8 *hdr,
struct nvbios_M0203E *);
#endif
...@@ -4,10 +4,13 @@ ...@@ -4,10 +4,13 @@
struct nouveau_bios; struct nouveau_bios;
enum dcb_i2c_type { enum dcb_i2c_type {
DCB_I2C_NV04_BIT = 0, /* matches bios type field prior to ccb 4.1 */
DCB_I2C_NV4E_BIT = 4, DCB_I2C_NV04_BIT = 0x00,
DCB_I2C_NVIO_BIT = 5, DCB_I2C_NV4E_BIT = 0x04,
DCB_I2C_NVIO_AUX = 6, DCB_I2C_NVIO_BIT = 0x05,
DCB_I2C_NVIO_AUX = 0x06,
/* made up - mostly */
DCB_I2C_PMGR = 0x80,
DCB_I2C_UNUSED = 0xff DCB_I2C_UNUSED = 0xff
}; };
...@@ -16,6 +19,7 @@ struct dcb_i2c_entry { ...@@ -16,6 +19,7 @@ struct dcb_i2c_entry {
u8 drive; u8 drive;
u8 sense; u8 sense;
u8 share; u8 share;
u8 auxch;
}; };
u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
......
#ifndef __NVBIOS_IMAGE_H__
#define __NVBIOS_IMAGE_H__
struct nvbios_image {
u32 base;
u32 size;
u8 type;
bool last;
};
bool nvbios_image(struct nouveau_bios *, int, struct nvbios_image *);
#endif
#ifndef __NVBIOS_NPDE_H__
#define __NVBIOS_NPDE_H__
struct nvbios_npdeT {
u32 image_size;
bool last;
};
u32 nvbios_npdeTe(struct nouveau_bios *, u32);
u32 nvbios_npdeTp(struct nouveau_bios *, u32, struct nvbios_npdeT *);
#endif
#ifndef __NVBIOS_PCIR_H__
#define __NVBIOS_PCIR_H__
struct nvbios_pcirT {
u16 vendor_id;
u16 device_id;
u8 class_code[3];
u32 image_size;
u16 image_rev;
u8 image_type;
bool last;
};
u32 nvbios_pcirTe(struct nouveau_bios *, u32, u8 *ver, u16 *hdr);
u32 nvbios_pcirTp(struct nouveau_bios *, u32, u8 *ver, u16 *hdr,
struct nvbios_pcirT *);
#endif
#ifndef __NVBIOS_PMU_H__
#define __NVBIOS_PMU_H__
struct nvbios_pmuT {
};
u32 nvbios_pmuTe(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u32 nvbios_pmuTp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_pmuT *);
struct nvbios_pmuE {
u8 type;
u32 data;
};
u32 nvbios_pmuEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
u32 nvbios_pmuEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
struct nvbios_pmuE *);
struct nvbios_pmuR {
u32 boot_addr_pmu;
u32 boot_addr;
u32 boot_size;
u32 code_addr_pmu;
u32 code_addr;
u32 code_size;
u32 init_addr_pmu;
u32 data_addr_pmu;
u32 data_addr;
u32 data_size;
u32 args_addr_pmu;
};
bool nvbios_pmuRm(struct nouveau_bios *, u8 type, struct nvbios_pmuR *);
#endif
...@@ -43,8 +43,9 @@ struct nvbios_ramcfg { ...@@ -43,8 +43,9 @@ struct nvbios_ramcfg {
unsigned ramcfg_10_02_08:1; unsigned ramcfg_10_02_08:1;
unsigned ramcfg_10_02_10:1; unsigned ramcfg_10_02_10:1;
unsigned ramcfg_10_02_20:1; unsigned ramcfg_10_02_20:1;
unsigned ramcfg_10_02_40:1; unsigned ramcfg_10_DLLoff:1;
unsigned ramcfg_10_03_0f:4; unsigned ramcfg_10_03_0f:4;
unsigned ramcfg_10_04_01:1;
unsigned ramcfg_10_05:8; unsigned ramcfg_10_05:8;
unsigned ramcfg_10_06:8; unsigned ramcfg_10_06:8;
unsigned ramcfg_10_07:8; unsigned ramcfg_10_07:8;
...@@ -95,9 +96,29 @@ struct nvbios_ramcfg { ...@@ -95,9 +96,29 @@ struct nvbios_ramcfg {
union { union {
struct { struct {
unsigned timing_10_WR:8; unsigned timing_10_WR:8;
unsigned timing_10_WTR:8;
unsigned timing_10_CL:8; unsigned timing_10_CL:8;
unsigned timing_10_RC:8;
/*empty: 4 */
unsigned timing_10_RFC:8; /* Byte 5 */
/*empty: 6 */
unsigned timing_10_RAS:8; /* Byte 7 */
/*empty: 8 */
unsigned timing_10_RP:8; /* Byte 9 */
unsigned timing_10_RCDRD:8;
unsigned timing_10_RCDWR:8;
unsigned timing_10_RRD:8;
unsigned timing_10_13:8;
unsigned timing_10_ODT:3; unsigned timing_10_ODT:3;
/* empty: 15 */
unsigned timing_10_16:8;
/* empty: 17 */
unsigned timing_10_18:8;
unsigned timing_10_CWL:8; unsigned timing_10_CWL:8;
unsigned timing_10_20:8;
unsigned timing_10_21:8;
/* empty: 22, 23 */
unsigned timing_10_24:8;
}; };
struct { struct {
unsigned timing_20_2e_03:2; unsigned timing_20_2e_03:2;
......
...@@ -30,5 +30,6 @@ extern struct nouveau_oclass *nva3_devinit_oclass; ...@@ -30,5 +30,6 @@ extern struct nouveau_oclass *nva3_devinit_oclass;
extern struct nouveau_oclass *nvaf_devinit_oclass; extern struct nouveau_oclass *nvaf_devinit_oclass;
extern struct nouveau_oclass *nvc0_devinit_oclass; extern struct nouveau_oclass *nvc0_devinit_oclass;
extern struct nouveau_oclass *gm107_devinit_oclass; extern struct nouveau_oclass *gm107_devinit_oclass;
extern struct nouveau_oclass *gm204_devinit_oclass;
#endif #endif
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <subdev/bios/i2c.h> #include <subdev/bios/i2c.h>
#define NV_I2C_PORT(n) (0x00 + (n)) #define NV_I2C_PORT(n) (0x00 + (n))
#define NV_I2C_AUX(n) (0x10 + (n))
#define NV_I2C_EXT(n) (0x20 + (n))
#define NV_I2C_DEFAULT(n) (0x80 + (n)) #define NV_I2C_DEFAULT(n) (0x80 + (n))
#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n)) #define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
...@@ -89,6 +91,7 @@ extern struct nouveau_oclass *nv94_i2c_oclass; ...@@ -89,6 +91,7 @@ extern struct nouveau_oclass *nv94_i2c_oclass;
extern struct nouveau_oclass *nvd0_i2c_oclass; extern struct nouveau_oclass *nvd0_i2c_oclass;
extern struct nouveau_oclass *gf117_i2c_oclass; extern struct nouveau_oclass *gf117_i2c_oclass;
extern struct nouveau_oclass *nve0_i2c_oclass; extern struct nouveau_oclass *nve0_i2c_oclass;
extern struct nouveau_oclass *gm204_i2c_oclass;
static inline int static inline int
nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg) nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
......
...@@ -48,6 +48,8 @@ void nouveau_memx_wait(struct nouveau_memx *, ...@@ -48,6 +48,8 @@ void nouveau_memx_wait(struct nouveau_memx *,
u32 addr, u32 mask, u32 data, u32 nsec); u32 addr, u32 mask, u32 data, u32 nsec);
void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec); void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
void nouveau_memx_wait_vblank(struct nouveau_memx *); void nouveau_memx_wait_vblank(struct nouveau_memx *);
void nouveau_memx_train(struct nouveau_memx *);
int nouveau_memx_train_result(struct nouveau_pwr *, u32 *, int);
void nouveau_memx_block(struct nouveau_memx *); void nouveau_memx_block(struct nouveau_memx *);
void nouveau_memx_unblock(struct nouveau_memx *); void nouveau_memx_unblock(struct nouveau_memx *);
......
...@@ -52,6 +52,7 @@ int _nouveau_volt_init(struct nouveau_object *); ...@@ -52,6 +52,7 @@ int _nouveau_volt_init(struct nouveau_object *);
#define _nouveau_volt_fini _nouveau_subdev_fini #define _nouveau_volt_fini _nouveau_subdev_fini
extern struct nouveau_oclass nv40_volt_oclass; extern struct nouveau_oclass nv40_volt_oclass;
extern struct nouveau_oclass gk20a_volt_oclass;
int nouveau_voltgpio_init(struct nouveau_volt *); int nouveau_voltgpio_init(struct nouveau_volt *);
int nouveau_voltgpio_get(struct nouveau_volt *); int nouveau_voltgpio_get(struct nouveau_volt *);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
......
/*
* 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 <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/M0203.h>
u32
nvbios_M0203Te(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
struct bit_entry bit_M;
u32 data = 0x00000000;
if (!bit_entry(bios, 'M', &bit_M)) {
if (bit_M.version == 2 && bit_M.length > 0x04)
data = nv_ro16(bios, bit_M.offset + 0x03);
if (data) {
*ver = nv_ro08(bios, data + 0x00);
switch (*ver) {
case 0x10:
*hdr = nv_ro08(bios, data + 0x01);
*len = nv_ro08(bios, data + 0x02);
*cnt = nv_ro08(bios, data + 0x03);
return data;
default:
break;
}
}
}
return 0x00000000;
}
u32
nvbios_M0203Tp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_M0203T *info)
{
u32 data = nvbios_M0203Te(bios, ver, hdr, cnt, len);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x10:
info->type = nv_ro08(bios, data + 0x04);
info->pointer = nv_ro16(bios, data + 0x05);
break;
default:
break;
}
return data;
}
u32
nvbios_M0203Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
{
u8 cnt, len;
u32 data = nvbios_M0203Te(bios, ver, hdr, &cnt, &len);
if (data && idx < cnt) {
data = data + *hdr + idx * len;
*hdr = len;
return data;
}
return 0x00000000;
}
u32
nvbios_M0203Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
struct nvbios_M0203E *info)
{
u32 data = nvbios_M0203Ee(bios, idx, ver, hdr);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x10:
info->type = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0;
info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4;
info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0;
return data;
default:
break;
}
return 0x00000000;
}
u32
nvbios_M0203Em(struct nouveau_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr,
struct nvbios_M0203E *info)
{
struct nvbios_M0203T M0203T;
u8 cnt, len, idx = 0xff;
u32 data;
if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) {
nv_warn(bios, "M0203T not found\n");
return 0x00000000;
}
while ((data = nvbios_M0203Ep(bios, ++idx, ver, hdr, info))) {
switch (M0203T.type) {
case M0203T_TYPE_RAMCFG:
if (info->strap != ramcfg)
continue;
return data;
default:
nv_warn(bios, "M0203T type %02x\n", M0203T.type);
return 0x00000000;
}
}
return data;
}
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include <subdev/bios/bmp.h> #include <subdev/bios/bmp.h>
#include <subdev/bios/bit.h> #include <subdev/bios/bit.h>
#include "priv.h"
u8 u8
nvbios_checksum(const u8 *data, int size) nvbios_checksum(const u8 *data, int size)
{ {
...@@ -56,362 +58,21 @@ nvbios_findstr(const u8 *data, int size, const char *str, int len) ...@@ -56,362 +58,21 @@ nvbios_findstr(const u8 *data, int size, const char *str, int len)
return 0; return 0;
} }
#if defined(__powerpc__) int
static void nvbios_extend(struct nouveau_bios *bios, u32 length)
nouveau_bios_shadow_of(struct nouveau_bios *bios)
{
struct pci_dev *pdev = nv_device(bios)->pdev;
struct device_node *dn;
const u32 *data;
int size;
dn = pci_device_to_OF_node(pdev);
if (!dn) {
nv_info(bios, "Unable to get the OF node\n");
return;
}
data = of_get_property(dn, "NVDA,BMP", &size);
if (data && size) {
bios->size = size;
bios->data = kmalloc(bios->size, GFP_KERNEL);
if (bios->data)
memcpy(bios->data, data, size);
}
}
#endif
static void
nouveau_bios_shadow_pramin(struct nouveau_bios *bios)
{
struct nouveau_device *device = nv_device(bios);
u64 addr = 0;
u32 bar0 = 0;
int i;
if (device->card_type >= NV_50) {
if (device->card_type >= NV_C0 && device->card_type < GM100) {
if (nv_rd32(bios, 0x022500) & 0x00000001)
return;
} else
if (device->card_type >= GM100) {
if (nv_rd32(bios, 0x021c04) & 0x00000001)
return;
}
addr = nv_rd32(bios, 0x619f04);
if (!(addr & 0x00000008)) {
nv_debug(bios, "... not enabled\n");
return;
}
if ( (addr & 0x00000003) != 1) {
nv_debug(bios, "... not in vram\n");
return;
}
addr = (addr & 0xffffff00) << 8;
if (!addr) {
addr = (u64)nv_rd32(bios, 0x001700) << 16;
addr += 0xf0000;
}
bar0 = nv_mask(bios, 0x001700, 0xffffffff, addr >> 16);
}
/* bail if no rom signature */
if (nv_rd08(bios, 0x700000) != 0x55 ||
nv_rd08(bios, 0x700001) != 0xaa)
goto out;
bios->size = nv_rd08(bios, 0x700002) * 512;
if (!bios->size)
goto out;
bios->data = kmalloc(bios->size, GFP_KERNEL);
if (bios->data) {
for (i = 0; i < bios->size; i++)
nv_wo08(bios, i, nv_rd08(bios, 0x700000 + i));
}
out:
if (device->card_type >= NV_50)
nv_wr32(bios, 0x001700, bar0);
}
static void
nouveau_bios_shadow_prom(struct nouveau_bios *bios)
{
struct nouveau_device *device = nv_device(bios);
u32 pcireg, access;
u16 pcir;
int i;
/* there is no prom on nv4x IGP's */
if (device->card_type == NV_40 && device->chipset >= 0x4c)
return;
/* enable access to rom */
if (device->card_type >= NV_50)
pcireg = 0x088050;
else
pcireg = 0x001850;
access = nv_mask(bios, pcireg, 0x00000001, 0x00000000);
/* WARNING: PROM accesses should always be 32-bits aligned. Other
* accesses work on most chipset but do not on Kepler chipsets
*/
/* bail if no rom signature, with a workaround for a PROM reading
* issue on some chipsets. the first read after a period of
* inactivity returns the wrong result, so retry the first header
* byte a few times before giving up as a workaround
*/
i = 16;
do {
u32 data = le32_to_cpu(nv_rd32(bios, 0x300000)) & 0xffff;
if (data == 0xaa55)
break;
} while (i--);
if (!i)
goto out;
/* read entire bios image to system memory */
bios->size = (le32_to_cpu(nv_rd32(bios, 0x300000)) >> 16) & 0xff;
bios->size = bios->size * 512;
if (!bios->size)
goto out;
bios->data = kmalloc(bios->size, GFP_KERNEL);
if (!bios->data)
goto out;
for (i = 0; i < bios->size; i += 4)
((u32 *)bios->data)[i/4] = nv_rd32(bios, 0x300000 + i);
/* check the PCI record header */
pcir = nv_ro16(bios, 0x0018);
if (bios->data[pcir + 0] != 'P' ||
bios->data[pcir + 1] != 'C' ||
bios->data[pcir + 2] != 'I' ||
bios->data[pcir + 3] != 'R') {
bios->size = 0;
kfree(bios->data);
}
out:
/* disable access to rom */
nv_wr32(bios, pcireg, access);
}
#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
#else
static inline bool
nouveau_acpi_rom_supported(struct pci_dev *pdev) {
return false;
}
static inline int
nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) {
return -EINVAL;
}
#endif
static void
nouveau_bios_shadow_acpi(struct nouveau_bios *bios)
{ {
struct pci_dev *pdev = nv_device(bios)->pdev; if (bios->size < length) {
int ret, cnt, i; u8 *prev = bios->data;
if (!(bios->data = kmalloc(length, GFP_KERNEL))) {
if (!nouveau_acpi_rom_supported(pdev)) { bios->data = prev;
bios->data = NULL; return -ENOMEM;
return;
} }
memcpy(bios->data, prev, bios->size);
bios->size = 0; bios->size = length;
bios->data = kmalloc(4096, GFP_KERNEL); kfree(prev);
if (bios->data) { return 1;
if (nouveau_acpi_get_bios_chunk(bios->data, 0, 4096) == 4096)
bios->size = bios->data[2] * 512;
kfree(bios->data);
} }
if (!bios->size)
return;
bios->data = kmalloc(bios->size, GFP_KERNEL);
if (bios->data) {
/* disobey the acpi spec - much faster on at least w530 ... */
ret = nouveau_acpi_get_bios_chunk(bios->data, 0, bios->size);
if (ret != bios->size ||
nvbios_checksum(bios->data, bios->size)) {
/* ... that didn't work, ok, i'll be good now */
for (i = 0; i < bios->size; i += cnt) {
cnt = min((bios->size - i), (u32)4096);
ret = nouveau_acpi_get_bios_chunk(bios->data, i, cnt);
if (ret != cnt)
break;
}
}
}
}
static void
nouveau_bios_shadow_pci(struct nouveau_bios *bios)
{
struct pci_dev *pdev = nv_device(bios)->pdev;
size_t size;
if (!pci_enable_rom(pdev)) {
void __iomem *rom = pci_map_rom(pdev, &size);
if (rom && size) {
bios->data = kmalloc(size, GFP_KERNEL);
if (bios->data) {
memcpy_fromio(bios->data, rom, size);
bios->size = size;
}
}
if (rom)
pci_unmap_rom(pdev, rom);
pci_disable_rom(pdev);
}
}
static void
nouveau_bios_shadow_platform(struct nouveau_bios *bios)
{
struct pci_dev *pdev = nv_device(bios)->pdev;
size_t size;
void __iomem *rom = pci_platform_rom(pdev, &size);
if (rom && size) {
bios->data = kmalloc(size, GFP_KERNEL);
if (bios->data) {
memcpy_fromio(bios->data, rom, size);
bios->size = size;
}
}
}
static int
nouveau_bios_score(struct nouveau_bios *bios, const bool writeable)
{
if (bios->size < 3 || !bios->data || bios->data[0] != 0x55 ||
bios->data[1] != 0xAA) {
nv_info(bios, "... signature not found\n");
return 0; return 0;
}
if (nvbios_checksum(bios->data,
min_t(u32, bios->data[2] * 512, bios->size))) {
nv_info(bios, "... checksum invalid\n");
/* if a ro image is somewhat bad, it's probably all rubbish */
return writeable ? 2 : 1;
}
nv_info(bios, "... appears to be valid\n");
return 3;
}
struct methods {
const char desc[16];
void (*shadow)(struct nouveau_bios *);
const bool rw;
int score;
u32 size;
u8 *data;
};
static int
nouveau_bios_shadow(struct nouveau_bios *bios)
{
struct methods shadow_methods[] = {
#if defined(__powerpc__)
{ "OpenFirmware", nouveau_bios_shadow_of, true, 0, 0, NULL },
#endif
{ "PRAMIN", nouveau_bios_shadow_pramin, true, 0, 0, NULL },
{ "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL },
{ "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL },
{ "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL },
{ "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL },
{}
};
struct methods *mthd, *best;
const struct firmware *fw;
const char *optarg;
int optlen, ret;
char *source;
optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
if (source) {
/* try to match one of the built-in methods */
mthd = shadow_methods;
do {
if (strcasecmp(source, mthd->desc))
continue;
nv_info(bios, "source: %s\n", mthd->desc);
mthd->shadow(bios);
mthd->score = nouveau_bios_score(bios, mthd->rw);
if (mthd->score) {
kfree(source);
return 0;
}
} while ((++mthd)->shadow);
/* attempt to load firmware image */
ret = request_firmware(&fw, source, &nv_device(bios)->pdev->dev);
if (ret == 0) {
bios->size = fw->size;
bios->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
release_firmware(fw);
nv_info(bios, "image: %s\n", source);
if (nouveau_bios_score(bios, 1)) {
kfree(source);
return 0;
}
kfree(bios->data);
bios->data = NULL;
}
nv_error(bios, "source \'%s\' invalid\n", source);
kfree(source);
}
mthd = shadow_methods;
do {
nv_info(bios, "checking %s for image...\n", mthd->desc);
mthd->shadow(bios);
mthd->score = nouveau_bios_score(bios, mthd->rw);
mthd->size = bios->size;
mthd->data = bios->data;
bios->data = NULL;
} while (mthd->score != 3 && (++mthd)->shadow);
mthd = shadow_methods;
best = mthd;
do {
if (mthd->score > best->score) {
kfree(best->data);
best = mthd;
}
} while ((++mthd)->shadow);
if (best->score) {
nv_info(bios, "using image from %s\n", best->desc);
bios->size = best->size;
bios->data = best->data;
return 0;
}
nv_error(bios, "unable to locate usable image\n");
return -EINVAL;
} }
static u8 static u8
...@@ -472,7 +133,7 @@ nouveau_bios_ctor(struct nouveau_object *parent, ...@@ -472,7 +133,7 @@ nouveau_bios_ctor(struct nouveau_object *parent,
if (ret) if (ret)
return ret; return ret;
ret = nouveau_bios_shadow(bios); ret = nvbios_shadow(bios);
if (ret) if (ret)
return ret; return ret;
......
...@@ -42,7 +42,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) ...@@ -42,7 +42,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
*ver = nv_ro08(bios, dcb); *ver = nv_ro08(bios, dcb);
if (*ver >= 0x41) { if (*ver >= 0x42) {
nv_warn(bios, "DCB version 0x%02x unknown\n", *ver); nv_warn(bios, "DCB version 0x%02x unknown\n", *ver);
return 0x0000; return 0x0000;
} else } else
...@@ -157,18 +157,21 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, ...@@ -157,18 +157,21 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
break; break;
} }
switch (conf & 0x0f000000) { outp->dpconf.link_nr = (conf & 0x0f000000) >> 24;
case 0x0f000000: if (*ver < 0x41) {
switch (outp->dpconf.link_nr) {
case 0x0f:
outp->dpconf.link_nr = 4; outp->dpconf.link_nr = 4;
break; break;
case 0x03000000: case 0x03:
outp->dpconf.link_nr = 2; outp->dpconf.link_nr = 2;
break; break;
case 0x01000000: case 0x01:
default: default:
outp->dpconf.link_nr = 1; outp->dpconf.link_nr = 1;
break; break;
} }
}
/* fall-through... */ /* fall-through... */
case DCB_OUTPUT_TMDS: case DCB_OUTPUT_TMDS:
......
...@@ -40,6 +40,7 @@ nvbios_disp_table(struct nouveau_bios *bios, ...@@ -40,6 +40,7 @@ nvbios_disp_table(struct nouveau_bios *bios,
switch (*ver) { switch (*ver) {
case 0x20: case 0x20:
case 0x21: case 0x21:
case 0x22:
*hdr = nv_ro08(bios, data + 0x01); *hdr = nv_ro08(bios, data + 0x01);
*len = nv_ro08(bios, data + 0x02); *len = nv_ro08(bios, data + 0x02);
*cnt = nv_ro08(bios, data + 0x03); *cnt = nv_ro08(bios, data + 0x03);
......
...@@ -41,6 +41,7 @@ nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) ...@@ -41,6 +41,7 @@ nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
case 0x21: case 0x21:
case 0x30: case 0x30:
case 0x40: case 0x40:
case 0x41:
*hdr = nv_ro08(bios, data + 0x01); *hdr = nv_ro08(bios, data + 0x01);
*len = nv_ro08(bios, data + 0x02); *len = nv_ro08(bios, data + 0x02);
*cnt = nv_ro08(bios, data + 0x03); *cnt = nv_ro08(bios, data + 0x03);
...@@ -70,6 +71,7 @@ nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx, ...@@ -70,6 +71,7 @@ nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx,
*cnt = nv_ro08(bios, outp + 0x04); *cnt = nv_ro08(bios, outp + 0x04);
break; break;
case 0x40: case 0x40:
case 0x41:
*hdr = nv_ro08(bios, data + 0x04); *hdr = nv_ro08(bios, data + 0x04);
*cnt = 0; *cnt = 0;
*len = 0; *len = 0;
...@@ -108,6 +110,7 @@ nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx, ...@@ -108,6 +110,7 @@ nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx,
info->script[4] = nv_ro16(bios, data + 0x10); info->script[4] = nv_ro16(bios, data + 0x10);
break; break;
case 0x40: case 0x40:
case 0x41:
info->flags = nv_ro08(bios, data + 0x04); info->flags = nv_ro08(bios, data + 0x04);
info->script[0] = nv_ro16(bios, data + 0x05); info->script[0] = nv_ro16(bios, data + 0x05);
info->script[1] = nv_ro16(bios, data + 0x07); info->script[1] = nv_ro16(bios, data + 0x07);
...@@ -172,10 +175,11 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, ...@@ -172,10 +175,11 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
break; break;
case 0x30: case 0x30:
case 0x40: case 0x40:
case 0x41:
info->pc = nv_ro08(bios, data + 0x00); info->pc = nv_ro08(bios, data + 0x00);
info->dc = nv_ro08(bios, data + 0x01); info->dc = nv_ro08(bios, data + 0x01);
info->pe = nv_ro08(bios, data + 0x02); info->pe = nv_ro08(bios, data + 0x02);
info->tx_pu = nv_ro08(bios, data + 0x03); info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f;
break; break;
default: default:
data = 0x0000; data = 0x0000;
...@@ -194,6 +198,10 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe, ...@@ -194,6 +198,10 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
u16 data; u16 data;
if (*ver >= 0x30) { if (*ver >= 0x30) {
/*XXX: there's a second set of these on at least 4.1, that
* i've witnessed nvidia using instead of the first
* on gm204. figure out what/why
*/
const u8 vsoff[] = { 0, 4, 7, 9 }; const u8 vsoff[] = { 0, 4, 7, 9 };
idx = (pc * 10) + vsoff[vs] + pe; idx = (pc * 10) + vsoff[vs] + pe;
} else { } else {
......
...@@ -90,7 +90,7 @@ nvbios_extdev_find(struct nouveau_bios *bios, enum nvbios_extdev_type type, ...@@ -90,7 +90,7 @@ nvbios_extdev_find(struct nouveau_bios *bios, enum nvbios_extdev_type type,
u16 entry; u16 entry;
i = 0; i = 0;
while (!(entry = nvbios_extdev_entry(bios, i++, &ver, &len))) { while ((entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
extdev_parse_entry(bios, entry, func); extdev_parse_entry(bios, entry, func);
if (func->type == type) if (func->type == type)
return 0; return 0;
......
...@@ -39,6 +39,11 @@ dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) ...@@ -39,6 +39,11 @@ dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
i2c = nv_ro16(bios, dcb + 4); i2c = nv_ro16(bios, dcb + 4);
} }
if (i2c && *ver >= 0x42) {
nv_warn(bios, "ccb %02x not supported\n", *ver);
return 0x0000;
}
if (i2c && *ver >= 0x30) { if (i2c && *ver >= 0x30) {
*ver = nv_ro08(bios, i2c + 0); *ver = nv_ro08(bios, i2c + 0);
*hdr = nv_ro08(bios, i2c + 1); *hdr = nv_ro08(bios, i2c + 1);
...@@ -70,14 +75,25 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info) ...@@ -70,14 +75,25 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
u8 ver, len; u8 ver, len;
u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
if (ent) { if (ent) {
info->type = nv_ro08(bios, ent + 3); if (ver >= 0x41) {
info->share = DCB_I2C_UNUSED; if (!(nv_ro32(bios, ent) & 0x80000000))
if (ver < 0x30) { info->type = DCB_I2C_UNUSED;
info->type &= 0x07; else
info->type = DCB_I2C_PMGR;
} else
if (ver >= 0x30) {
info->type = nv_ro08(bios, ent + 0x03);
} else {
info->type = nv_ro08(bios, ent + 0x03) & 0x07;
if (info->type == 0x07) if (info->type == 0x07)
info->type = DCB_I2C_UNUSED; info->type = DCB_I2C_UNUSED;
} }
info->drive = DCB_I2C_UNUSED;
info->sense = DCB_I2C_UNUSED;
info->share = DCB_I2C_UNUSED;
info->auxch = DCB_I2C_UNUSED;
switch (info->type) { switch (info->type) {
case DCB_I2C_NV04_BIT: case DCB_I2C_NV04_BIT:
info->drive = nv_ro08(bios, ent + 0); info->drive = nv_ro08(bios, ent + 0);
...@@ -87,12 +103,23 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info) ...@@ -87,12 +103,23 @@ dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
info->drive = nv_ro08(bios, ent + 1); info->drive = nv_ro08(bios, ent + 1);
return 0; return 0;
case DCB_I2C_NVIO_BIT: case DCB_I2C_NVIO_BIT:
case DCB_I2C_NVIO_AUX:
info->drive = nv_ro08(bios, ent + 0) & 0x0f; info->drive = nv_ro08(bios, ent + 0) & 0x0f;
if (nv_ro08(bios, ent + 1) & 0x01) { if (nv_ro08(bios, ent + 1) & 0x01)
info->share = nv_ro08(bios, ent + 1) >> 1; info->share = nv_ro08(bios, ent + 1) >> 1;
info->share &= 0x0f; return 0;
} case DCB_I2C_NVIO_AUX:
info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
if (nv_ro08(bios, ent + 1) & 0x01)
info->share = info->auxch;
return 0;
case DCB_I2C_PMGR:
info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0;
if (info->drive == 0x1f)
info->drive = DCB_I2C_UNUSED;
info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5;
if (info->auxch == 0x1f)
info->auxch = DCB_I2C_UNUSED;
info->share = info->auxch;
return 0; return 0;
case DCB_I2C_UNUSED: case DCB_I2C_UNUSED:
return 0; return 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 <bskeggs@redhat.com>
*/
#include <subdev/bios.h>
#include <subdev/bios/image.h>
#include <subdev/bios/pcir.h>
#include <subdev/bios/npde.h>
static bool
nvbios_imagen(struct nouveau_bios *bios, struct nvbios_image *image)
{
struct nvbios_pcirT pcir;
struct nvbios_npdeT npde;
u8 ver;
u16 hdr;
u32 data;
switch ((data = nv_ro16(bios, image->base + 0x00))) {
case 0xaa55:
case 0xbb77:
case 0x4e56: /* NV */
break;
default:
nv_debug(bios, "%08x: ROM signature (%04x) unknown\n",
image->base, data);
return false;
}
if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir)))
return false;
image->size = pcir.image_size;
image->type = pcir.image_type;
image->last = pcir.last;
if (image->type != 0x70) {
if (!(data = nvbios_npdeTp(bios, image->base, &npde)))
return true;
image->size = npde.image_size;
image->last = npde.last;
} else {
image->last = true;
}
return true;
}
bool
nvbios_image(struct nouveau_bios *bios, int idx, struct nvbios_image *image)
{
memset(image, 0x00, sizeof(*image));
do {
image->base += image->size;
if (image->last || !nvbios_imagen(bios, image))
return false;
} while(idx--);
return true;
}
...@@ -255,6 +255,8 @@ init_i2c(struct nvbios_init *init, int index) ...@@ -255,6 +255,8 @@ init_i2c(struct nvbios_init *init, int index)
} }
index = init->outp->i2c_index; index = init->outp->i2c_index;
if (init->outp->type == DCB_OUTPUT_DP)
index += NV_I2C_AUX(0);
} }
return i2c->find(i2c, index); return i2c->find(i2c, index);
...@@ -278,7 +280,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val) ...@@ -278,7 +280,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
return -ENODEV; return -ENODEV;
} }
static int static u8
init_rdauxr(struct nvbios_init *init, u32 addr) init_rdauxr(struct nvbios_init *init, u32 addr)
{ {
struct nouveau_i2c_port *port = init_i2c(init, -2); struct nouveau_i2c_port *port = init_i2c(init, -2);
...@@ -286,20 +288,24 @@ init_rdauxr(struct nvbios_init *init, u32 addr) ...@@ -286,20 +288,24 @@ init_rdauxr(struct nvbios_init *init, u32 addr)
if (port && init_exec(init)) { if (port && init_exec(init)) {
int ret = nv_rdaux(port, addr, &data, 1); int ret = nv_rdaux(port, addr, &data, 1);
if (ret) if (ret == 0)
return ret;
return data; return data;
trace("auxch read failed with %d\n", ret);
} }
return -ENODEV; return 0x00;
} }
static int static int
init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
{ {
struct nouveau_i2c_port *port = init_i2c(init, -2); struct nouveau_i2c_port *port = init_i2c(init, -2);
if (port && init_exec(init)) if (port && init_exec(init)) {
return nv_wraux(port, addr, &data, 1); int ret = nv_wraux(port, addr, &data, 1);
if (ret)
trace("auxch write failed with %d\n", ret);
return ret;
}
return -ENODEV; return -ENODEV;
} }
...@@ -837,6 +843,40 @@ init_io_or(struct nvbios_init *init) ...@@ -837,6 +843,40 @@ init_io_or(struct nvbios_init *init)
init_wrvgai(init, 0x03d4, index, data | (1 << or)); init_wrvgai(init, 0x03d4, index, data | (1 << or));
} }
/**
* INIT_ANDN_REG - opcode 0x47
*
*/
static void
init_andn_reg(struct nvbios_init *init)
{
struct nouveau_bios *bios = init->bios;
u32 reg = nv_ro32(bios, init->offset + 1);
u32 mask = nv_ro32(bios, init->offset + 5);
trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask);
init->offset += 9;
init_mask(init, reg, mask, 0);
}
/**
* INIT_OR_REG - opcode 0x48
*
*/
static void
init_or_reg(struct nvbios_init *init)
{
struct nouveau_bios *bios = init->bios;
u32 reg = nv_ro32(bios, init->offset + 1);
u32 mask = nv_ro32(bios, init->offset + 5);
trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask);
init->offset += 9;
init_mask(init, reg, 0, mask);
}
/** /**
* INIT_INDEX_ADDRESS_LATCHED - opcode 0x49 * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
* *
...@@ -2068,6 +2108,8 @@ static struct nvbios_init_opcode { ...@@ -2068,6 +2108,8 @@ static struct nvbios_init_opcode {
[0x3a] = { init_dp_condition }, [0x3a] = { init_dp_condition },
[0x3b] = { init_io_mask_or }, [0x3b] = { init_io_mask_or },
[0x3c] = { init_io_or }, [0x3c] = { init_io_or },
[0x47] = { init_andn_reg },
[0x48] = { init_or_reg },
[0x49] = { init_idx_addr_latched }, [0x49] = { init_idx_addr_latched },
[0x4a] = { init_io_restrict_pll2 }, [0x4a] = { init_io_restrict_pll2 },
[0x4b] = { init_pll2 }, [0x4b] = { init_pll2 },
......
/*
* 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 <bskeggs@redhat.com>
*/
#include <subdev/bios.h>
#include <subdev/bios/npde.h>
#include <subdev/bios/pcir.h>
u32
nvbios_npdeTe(struct nouveau_bios *bios, u32 base)
{
struct nvbios_pcirT pcir;
u8 ver; u16 hdr;
u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir);
if (data = (data + hdr + 0x0f) & ~0x0f, data) {
switch (nv_ro32(bios, data + 0x00)) {
case 0x4544504e: /* NPDE */
break;
default:
nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n",
data, nv_ro32(bios, data + 0x00));
data = 0;
break;
}
}
return data;
}
u32
nvbios_npdeTp(struct nouveau_bios *bios, u32 base, struct nvbios_npdeT *info)
{
u32 data = nvbios_npdeTe(bios, base);
memset(info, 0x00, sizeof(*info));
if (data) {
info->image_size = nv_ro16(bios, data + 0x08) * 512;
info->last = nv_ro08(bios, data + 0x0a) & 0x80;
}
return data;
}
/*
* 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 <bskeggs@redhat.com>
*/
#include <subdev/bios.h>
#include <subdev/bios/pcir.h>
u32
nvbios_pcirTe(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr)
{
u32 data = nv_ro16(bios, base + 0x18);
if (data) {
data += base;
switch (nv_ro32(bios, data + 0x00)) {
case 0x52494350: /* PCIR */
case 0x53494752: /* RGIS */
case 0x5344504e: /* NPDS */
*hdr = nv_ro16(bios, data + 0x0a);
*ver = nv_ro08(bios, data + 0x0c);
break;
default:
nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n",
data, nv_ro32(bios, data + 0x00));
data = 0;
break;
}
}
return data;
}
u32
nvbios_pcirTp(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr,
struct nvbios_pcirT *info)
{
u32 data = nvbios_pcirTe(bios, base, ver, hdr);
memset(info, 0x00, sizeof(*info));
if (data) {
info->vendor_id = nv_ro16(bios, data + 0x04);
info->device_id = nv_ro16(bios, data + 0x06);
info->class_code[0] = nv_ro08(bios, data + 0x0d);
info->class_code[1] = nv_ro08(bios, data + 0x0e);
info->class_code[2] = nv_ro08(bios, data + 0x0f);
info->image_size = nv_ro16(bios, data + 0x10) * 512;
info->image_rev = nv_ro16(bios, data + 0x12);
info->image_type = nv_ro08(bios, data + 0x14);
info->last = nv_ro08(bios, data + 0x15) & 0x80;
}
return data;
}
/*
* 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 <bskeggs@redhat.com>
*/
#include <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/image.h>
#include <subdev/bios/pmu.h>
static u32
weirdo_pointer(struct nouveau_bios *bios, u32 data)
{
struct nvbios_image image;
int idx = 0;
if (nvbios_image(bios, idx++, &image)) {
data -= image.size;
while (nvbios_image(bios, idx++, &image)) {
if (image.type == 0xe0)
return image.base + data;
}
}
return 0;
}
u32
nvbios_pmuTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
struct bit_entry bit_p;
u32 data = 0;
if (!bit_entry(bios, 'p', &bit_p)) {
if (bit_p.version == 2 && bit_p.length >= 4)
data = nv_ro32(bios, bit_p.offset + 0x00);
if ((data = weirdo_pointer(bios, data))) {
*ver = nv_ro08(bios, data + 0x00); /* maybe? */
*hdr = nv_ro08(bios, data + 0x01);
*len = nv_ro08(bios, data + 0x02);
*cnt = nv_ro08(bios, data + 0x03);
}
}
return data;
}
u32
nvbios_pmuTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_pmuT *info)
{
u32 data = nvbios_pmuTe(bios, ver, hdr, cnt, len);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
default:
break;
}
return data;
}
u32
nvbios_pmuEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
{
u8 cnt, len;
u32 data = nvbios_pmuTe(bios, ver, hdr, &cnt, &len);
if (data && idx < cnt) {
data = data + *hdr + (idx * len);
*hdr = len;
return data;
}
return 0;
}
u32
nvbios_pmuEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
struct nvbios_pmuE *info)
{
u32 data = nvbios_pmuEe(bios, idx, ver, hdr);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
default:
info->type = nv_ro08(bios, data + 0x00);
info->data = nv_ro32(bios, data + 0x02);
break;
}
return data;
}
bool
nvbios_pmuRm(struct nouveau_bios *bios, u8 type, struct nvbios_pmuR *info)
{
struct nvbios_pmuE pmuE;
u8 ver, hdr, idx = 0;
u32 data;
memset(info, 0x00, sizeof(*info));
while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) {
if ( pmuE.type == type &&
(data = weirdo_pointer(bios, pmuE.data))) {
info->init_addr_pmu = nv_ro32(bios, data + 0x08);
info->args_addr_pmu = nv_ro32(bios, data + 0x0c);
info->boot_addr = data + 0x30;
info->boot_addr_pmu = nv_ro32(bios, data + 0x10) +
nv_ro32(bios, data + 0x18);
info->boot_size = nv_ro32(bios, data + 0x1c) -
nv_ro32(bios, data + 0x18);
info->code_addr = info->boot_addr + info->boot_size;
info->code_addr_pmu = info->boot_addr_pmu +
info->boot_size;
info->code_size = nv_ro32(bios, data + 0x20);
info->data_addr = data + 0x30 +
nv_ro32(bios, data + 0x24);
info->data_addr_pmu = nv_ro32(bios, data + 0x28);
info->data_size = nv_ro32(bios, data + 0x2c);
return true;
}
}
return false;
}
#ifndef __NVKM_BIOS_PRIV_H__
#define __NVKM_BIOS_PRIV_H__
#include <subdev/bios.h>
struct nvbios_source {
const char *name;
void *(*init)(struct nouveau_bios *, const char *);
void (*fini)(void *);
u32 (*read)(void *, u32 offset, u32 length, struct nouveau_bios *);
bool rw;
};
int nvbios_extend(struct nouveau_bios *, u32 length);
int nvbios_shadow(struct nouveau_bios *);
extern const struct nvbios_source nvbios_rom;
extern const struct nvbios_source nvbios_ramin;
extern const struct nvbios_source nvbios_acpi_fast;
extern const struct nvbios_source nvbios_acpi_slow;
extern const struct nvbios_source nvbios_pcirom;
extern const struct nvbios_source nvbios_platform;
extern const struct nvbios_source nvbios_of;
#endif
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/bit.h> #include <subdev/bios/bit.h>
#include <subdev/bios/ramcfg.h> #include <subdev/bios/ramcfg.h>
#include <subdev/bios/M0203.h>
static u8 static u8
nvbios_ramcfg_strap(struct nouveau_subdev *subdev) nvbios_ramcfg_strap(struct nouveau_subdev *subdev)
...@@ -54,13 +55,23 @@ nvbios_ramcfg_index(struct nouveau_subdev *subdev) ...@@ -54,13 +55,23 @@ nvbios_ramcfg_index(struct nouveau_subdev *subdev)
u8 strap = nvbios_ramcfg_strap(subdev); u8 strap = nvbios_ramcfg_strap(subdev);
u32 xlat = 0x00000000; u32 xlat = 0x00000000;
struct bit_entry bit_M; struct bit_entry bit_M;
struct nvbios_M0203E M0203E;
u8 ver, hdr;
if (!bit_entry(bios, 'M', &bit_M)) { if (!bit_entry(bios, 'M', &bit_M)) {
if (bit_M.version == 1 && bit_M.length >= 5) if (bit_M.version == 1 && bit_M.length >= 5)
xlat = nv_ro16(bios, bit_M.offset + 3); xlat = nv_ro16(bios, bit_M.offset + 3);
if (bit_M.version == 2 && bit_M.length >= 3) if (bit_M.version == 2 && bit_M.length >= 3) {
/*XXX: is M ever shorter than this?
* if not - what is xlat used for now?
* also - sigh..
*/
if (bit_M.length >= 7 &&
nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E))
return M0203E.group;
xlat = nv_ro16(bios, bit_M.offset + 1); xlat = nv_ro16(bios, bit_M.offset + 1);
} }
}
if (xlat) if (xlat)
strap = nv_ro08(bios, xlat + strap); strap = nv_ro08(bios, xlat + strap);
......
...@@ -162,8 +162,9 @@ nvbios_rammapSp(struct nouveau_bios *bios, u32 data, ...@@ -162,8 +162,9 @@ nvbios_rammapSp(struct nouveau_bios *bios, u32 data,
p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5; p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
p->ramcfg_10_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0;
p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0; p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0; p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 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 <bskeggs@redhat.com>
*/
#include "priv.h"
#include <core/option.h>
#include <subdev/bios/image.h>
struct shadow {
struct nouveau_oclass base;
u32 skip;
const struct nvbios_source *func;
void *data;
u32 size;
int score;
};
static bool
shadow_fetch(struct nouveau_bios *bios, u32 upto)
{
struct shadow *mthd = (void *)nv_object(bios)->oclass;
const u32 limit = (upto + 3) & ~3;
const u32 start = bios->size;
void *data = mthd->data;
if (nvbios_extend(bios, limit) > 0) {
u32 read = mthd->func->read(data, start, limit - start, bios);
bios->size = start + read;
}
return bios->size >= limit;
}
static u8
shadow_rd08(struct nouveau_object *object, u64 addr)
{
struct nouveau_bios *bios = (void *)object;
if (shadow_fetch(bios, addr + 1))
return bios->data[addr];
return 0x00;
}
static u16
shadow_rd16(struct nouveau_object *object, u64 addr)
{
struct nouveau_bios *bios = (void *)object;
if (shadow_fetch(bios, addr + 2))
return get_unaligned_le16(&bios->data[addr]);
return 0x0000;
}
static u32
shadow_rd32(struct nouveau_object *object, u64 addr)
{
struct nouveau_bios *bios = (void *)object;
if (shadow_fetch(bios, addr + 4))
return get_unaligned_le32(&bios->data[addr]);
return 0x00000000;
}
static struct nouveau_oclass
shadow_class = {
.handle = NV_SUBDEV(VBIOS, 0x00),
.ofuncs = &(struct nouveau_ofuncs) {
.rd08 = shadow_rd08,
.rd16 = shadow_rd16,
.rd32 = shadow_rd32,
},
};
static int
shadow_image(struct nouveau_bios *bios, int idx, struct shadow *mthd)
{
struct nvbios_image image;
int score = 1;
if (!nvbios_image(bios, idx, &image)) {
nv_debug(bios, "image %d invalid\n", idx);
return 0;
}
nv_debug(bios, "%08x: type %02x, %d bytes\n",
image.base, image.type, image.size);
if (!shadow_fetch(bios, image.size)) {
nv_debug(bios, "%08x: fetch failed\n", image.base);
return 0;
}
switch (image.type) {
case 0x00:
if (nvbios_checksum(&bios->data[image.base], image.size)) {
nv_debug(bios, "%08x: checksum failed\n", image.base);
if (mthd->func->rw)
score += 1;
score += 1;
} else {
score += 3;
}
break;
default:
score += 3;
break;
}
if (!image.last)
score += shadow_image(bios, idx + 1, mthd);
return score;
}
static int
shadow_score(struct nouveau_bios *bios, struct shadow *mthd)
{
struct nouveau_oclass *oclass = nv_object(bios)->oclass;
int score;
nv_object(bios)->oclass = &mthd->base;
score = shadow_image(bios, 0, mthd);
nv_object(bios)->oclass = oclass;
return score;
}
static int
shadow_method(struct nouveau_bios *bios, struct shadow *mthd, const char *name)
{
const struct nvbios_source *func = mthd->func;
if (func->name) {
nv_debug(bios, "trying %s...\n", name ? name : func->name);
if (func->init) {
mthd->data = func->init(bios, name);
if (IS_ERR(mthd->data)) {
mthd->data = NULL;
return 0;
}
}
mthd->score = shadow_score(bios, mthd);
if (func->fini)
func->fini(mthd->data);
nv_debug(bios, "scored %d\n", mthd->score);
mthd->data = bios->data;
mthd->size = bios->size;
bios->data = NULL;
bios->size = 0;
}
return mthd->score;
}
static u32
shadow_fw_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
{
const struct firmware *fw = data;
if (offset + length <= fw->size) {
memcpy(bios->data + offset, fw->data + offset, length);
return length;
}
return 0;
}
static void *
shadow_fw_init(struct nouveau_bios *bios, const char *name)
{
struct device *dev = &nv_device(bios)->pdev->dev;
const struct firmware *fw;
int ret = request_firmware(&fw, name, dev);
if (ret)
return ERR_PTR(-ENOENT);
return (void *)fw;
}
static const struct nvbios_source
shadow_fw = {
.name = "firmware",
.init = shadow_fw_init,
.fini = (void(*)(void *))release_firmware,
.read = shadow_fw_read,
.rw = false,
};
int
nvbios_shadow(struct nouveau_bios *bios)
{
struct shadow mthds[] = {
{ shadow_class, 0, &nvbios_of },
{ shadow_class, 0, &nvbios_ramin },
{ shadow_class, 0, &nvbios_rom },
{ shadow_class, 0, &nvbios_acpi_fast },
{ shadow_class, 4, &nvbios_acpi_slow },
{ shadow_class, 1, &nvbios_pcirom },
{ shadow_class, 1, &nvbios_platform },
{ shadow_class }
}, *mthd = mthds, *best = NULL;
const char *optarg;
char *source;
int optlen;
/* handle user-specified bios source */
optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
if (source) {
/* try to match one of the built-in methods */
for (mthd = mthds; mthd->func; mthd++) {
if (mthd->func->name &&
!strcasecmp(source, mthd->func->name)) {
best = mthd;
if (shadow_method(bios, mthd, NULL))
break;
}
}
/* otherwise, attempt to load as firmware */
if (!best && (best = mthd)) {
mthd->func = &shadow_fw;
shadow_method(bios, mthd, source);
mthd->func = NULL;
}
if (!best->score) {
nv_error(bios, "%s invalid\n", source);
kfree(source);
source = NULL;
}
}
/* scan all potential bios sources, looking for best image */
if (!best || !best->score) {
for (mthd = mthds, best = mthd; mthd->func; mthd++) {
if (!mthd->skip || best->score < mthd->skip) {
if (shadow_method(bios, mthd, NULL)) {
if (mthd->score > best->score)
best = mthd;
}
}
}
}
/* cleanup the ones we didn't use */
for (mthd = mthds; mthd->func; mthd++) {
if (mthd != best)
kfree(mthd->data);
}
if (!best->score) {
nv_fatal(bios, "unable to locate usable image\n");
return -EINVAL;
}
nv_info(bios, "using image from %s\n", best->func ?
best->func->name : source);
bios->data = best->data;
bios->size = best->size;
kfree(source);
return 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.
*
*/
#include "priv.h"
#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
#else
static inline bool
nouveau_acpi_rom_supported(struct pci_dev *pdev)
{
return false;
}
static inline int
nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
{
return -EINVAL;
}
#endif
/* This version of the shadow function disobeys the ACPI spec and tries
* to fetch in units of more than 4KiB at a time. This is a LOT faster
* on some systems, such as Lenovo W530.
*/
static u32
acpi_read_fast(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
{
u32 limit = (offset + length + 0xfff) & ~0xfff;
u32 start = offset & ~0x00000fff;
u32 fetch = limit - start;
if (nvbios_extend(bios, limit) > 0) {
int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch);
if (ret == fetch)
return fetch;
}
return 0;
}
/* Other systems, such as the one in fdo#55948, will report a success
* but only return 4KiB of data. The common bios fetching logic will
* detect an invalid image, and fall back to this version of the read
* function.
*/
static u32
acpi_read_slow(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
{
u32 limit = (offset + length + 0xfff) & ~0xfff;
u32 start = offset & ~0xfff;
u32 fetch = 0;
if (nvbios_extend(bios, limit) > 0) {
while (start + fetch < limit) {
int ret = nouveau_acpi_get_bios_chunk(bios->data,
start + fetch,
0x1000);
if (ret != 0x1000)
break;
fetch += 0x1000;
}
}
return fetch;
}
static void *
acpi_init(struct nouveau_bios *bios, const char *name)
{
if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev))
return ERR_PTR(-ENODEV);
return NULL;
}
const struct nvbios_source
nvbios_acpi_fast = {
.name = "ACPI",
.init = acpi_init,
.read = acpi_read_fast,
.rw = false,
};
const struct nvbios_source
nvbios_acpi_slow = {
.name = "ACPI",
.init = acpi_init,
.read = acpi_read_slow,
.rw = false,
};
/*
* 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.
*
*/
#include "priv.h"
#if defined(__powerpc__)
struct priv {
const void __iomem *data;
int size;
};
static u32
of_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
{
struct priv *priv = data;
if (offset + length <= priv->size) {
memcpy_fromio(bios->data + offset, priv->data + offset, length);
return length;
}
return 0;
}
static void *
of_init(struct nouveau_bios *bios, const char *name)
{
struct pci_dev *pdev = nv_device(bios)->pdev;
struct device_node *dn;
struct priv *priv;
if (!(dn = pci_device_to_OF_node(pdev)))
return ERR_PTR(-ENODEV);
if (!(priv = kzalloc(sizeof(*priv), GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
if ((priv->data = of_get_property(dn, "NVDA,BMP", &priv->size)))
return priv;
kfree(priv);
return ERR_PTR(-EINVAL);
}
const struct nvbios_source
nvbios_of = {
.name = "OpenFirmware",
.init = of_init,
.fini = (void(*)(void *))kfree,
.read = of_read,
.rw = false,
};
#else
const struct nvbios_source
nvbios_of = {
};
#endif
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "priv.h"
struct priv {
struct pci_dev *pdev;
void __iomem *rom;
size_t size;
};
static u32
pcirom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
{
struct priv *priv = data;
if (offset + length <= priv->size) {
memcpy_fromio(bios->data + offset, priv->rom + offset, length);
return length;
}
return 0;
}
static void
pcirom_fini(void *data)
{
struct priv *priv = data;
pci_unmap_rom(priv->pdev, priv->rom);
pci_disable_rom(priv->pdev);
kfree(priv);
}
static void *
pcirom_init(struct nouveau_bios *bios, const char *name)
{
struct pci_dev *pdev = nv_device(bios)->pdev;
struct priv *priv = NULL;
int ret;
if (!(ret = pci_enable_rom(pdev))) {
if (ret = -ENOMEM,
(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
if (ret = -EFAULT,
(priv->rom = pci_map_rom(pdev, &priv->size))) {
priv->pdev = pdev;
return priv;
}
kfree(priv);
}
pci_disable_rom(pdev);
}
return ERR_PTR(ret);
}
const struct nvbios_source
nvbios_pcirom = {
.name = "PCIROM",
.init = pcirom_init,
.fini = pcirom_fini,
.read = pcirom_read,
.rw = true,
};
static void *
platform_init(struct nouveau_bios *bios, const char *name)
{
struct pci_dev *pdev = nv_device(bios)->pdev;
struct priv *priv;
int ret = -ENOMEM;
if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
if (ret = -ENODEV,
(priv->rom = pci_platform_rom(pdev, &priv->size)))
return priv;
kfree(priv);
}
return ERR_PTR(ret);
}
const struct nvbios_source
nvbios_platform = {
.name = "PLATFORM",
.init = platform_init,
.fini = (void(*)(void *))kfree,
.read = pcirom_read,
.rw = true,
};
/*
* 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.
*
*/
#include "priv.h"
struct priv {
struct nouveau_bios *bios;
u32 bar0;
};
static u32
pramin_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
{
u32 i;
if (offset + length <= 0x00100000) {
for (i = offset; i < offset + length; i += 4)
*(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i);
return length;
}
return 0;
}
static void
pramin_fini(void *data)
{
struct priv *priv = data;
nv_wr32(priv->bios, 0x001700, priv->bar0);
kfree(priv);
}
static void *
pramin_init(struct nouveau_bios *bios, const char *name)
{
struct priv *priv = NULL;
u64 addr = 0;
/* PRAMIN always potentially available prior to nv50 */
if (nv_device(bios)->card_type < NV_50)
return NULL;
/* we can't get the bios image pointer without PDISP */
if (nv_device(bios)->card_type >= GM100)
addr = nv_rd32(bios, 0x021c04);
else
if (nv_device(bios)->card_type >= NV_C0)
addr = nv_rd32(bios, 0x022500);
if (addr & 0x00000001) {
nv_debug(bios, "... display disabled\n");
return ERR_PTR(-ENODEV);
}
/* check that the window is enabled and in vram, particularly
* important as we don't want to be touching vram on an
* uninitialised board
*/
addr = nv_rd32(bios, 0x619f04);
if (!(addr & 0x00000008)) {
nv_debug(bios, "... not enabled\n");
return ERR_PTR(-ENODEV);
}
if ( (addr & 0x00000003) != 1) {
nv_debug(bios, "... not in vram\n");
return ERR_PTR(-ENODEV);
}
/* some alternate method inherited from xf86-video-nv... */
addr = (addr & 0xffffff00) << 8;
if (!addr) {
addr = (u64)nv_rd32(bios, 0x001700) << 16;
addr += 0xf0000;
}
/* modify bar0 PRAMIN window to cover the bios image */
if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
nv_error(bios, "... out of memory\n");
return ERR_PTR(-ENOMEM);
}
priv->bios = bios;
priv->bar0 = nv_rd32(bios, 0x001700);
nv_wr32(bios, 0x001700, addr >> 16);
return priv;
}
const struct nvbios_source
nvbios_ramin = {
.name = "PRAMIN",
.init = pramin_init,
.fini = pramin_fini,
.read = pramin_read,
.rw = true,
};
/*
* 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.
*
*/
#include "priv.h"
static u32
prom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
{
u32 i;
if (offset + length <= 0x00100000) {
for (i = offset; i < offset + length; i += 4)
*(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i);
return length;
}
return 0;
}
static void
prom_fini(void *data)
{
struct nouveau_bios *bios = data;
if (nv_device(bios)->card_type < NV_50)
nv_mask(bios, 0x001850, 0x00000001, 0x00000001);
else
nv_mask(bios, 0x088050, 0x00000001, 0x00000001);
}
static void *
prom_init(struct nouveau_bios *bios, const char *name)
{
if (nv_device(bios)->card_type < NV_50) {
if (nv_device(bios)->card_type == NV_40 &&
nv_device(bios)->chipset >= 0x4c)
return ERR_PTR(-ENODEV);
nv_mask(bios, 0x001850, 0x00000001, 0x00000000);
} else {
nv_mask(bios, 0x088050, 0x00000001, 0x00000000);
}
return bios;
}
const struct nvbios_source
nvbios_rom = {
.name = "PROM",
.init = prom_init,
.fini = prom_fini,
.read = prom_read,
.rw = false,
};
...@@ -94,9 +94,43 @@ nvbios_timingEp(struct nouveau_bios *bios, int idx, ...@@ -94,9 +94,43 @@ nvbios_timingEp(struct nouveau_bios *bios, int idx,
switch (!!data * *ver) { switch (!!data * *ver) {
case 0x10: case 0x10:
p->timing_10_WR = nv_ro08(bios, data + 0x00); p->timing_10_WR = nv_ro08(bios, data + 0x00);
p->timing_10_WTR = nv_ro08(bios, data + 0x01);
p->timing_10_CL = nv_ro08(bios, data + 0x02); p->timing_10_CL = nv_ro08(bios, data + 0x02);
p->timing_10_RC = nv_ro08(bios, data + 0x03);
p->timing_10_RFC = nv_ro08(bios, data + 0x05);
p->timing_10_RAS = nv_ro08(bios, data + 0x07);
p->timing_10_RP = nv_ro08(bios, data + 0x09);
p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a);
p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b);
p->timing_10_RRD = nv_ro08(bios, data + 0x0c);
p->timing_10_13 = nv_ro08(bios, data + 0x0d);
p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07; p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07;
p->timing_10_24 = 0xff;
p->timing_10_21 = 0;
p->timing_10_20 = 0;
p->timing_10_CWL = 0;
p->timing_10_18 = 0;
p->timing_10_16 = 0;
switch (min_t(u8, *hdr, 25)) {
case 25:
p->timing_10_24 = nv_ro08(bios, data + 0x18);
case 24:
case 23:
case 22:
p->timing_10_21 = nv_ro08(bios, data + 0x15);
case 21:
p->timing_10_20 = nv_ro08(bios, data + 0x14);
case 20:
p->timing_10_CWL = nv_ro08(bios, data + 0x13); p->timing_10_CWL = nv_ro08(bios, data + 0x13);
case 19:
p->timing_10_18 = nv_ro08(bios, data + 0x12);
case 18:
case 17:
p->timing_10_16 = nv_ro08(bios, data + 0x10);
}
break; break;
case 0x20: case 0x20:
p->timing[0] = nv_ro32(bios, data + 0x00); p->timing[0] = nv_ro32(bios, data + 0x00);
......
...@@ -109,7 +109,7 @@ struct gk20a_clk_pllg_params { ...@@ -109,7 +109,7 @@ struct gk20a_clk_pllg_params {
}; };
static const struct gk20a_clk_pllg_params gk20a_pllg_params = { static const struct gk20a_clk_pllg_params gk20a_pllg_params = {
.min_vco = 1000, .max_vco = 1700, .min_vco = 1000, .max_vco = 2064,
.min_u = 12, .max_u = 38, .min_u = 12, .max_u = 38,
.min_m = 1, .max_m = 255, .min_m = 1, .max_m = 255,
.min_n = 8, .max_n = 255, .min_n = 8, .max_n = 255,
...@@ -470,76 +470,91 @@ gk20a_pstates[] = { ...@@ -470,76 +470,91 @@ gk20a_pstates[] = {
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 72000, .domain[nv_clk_src_gpc] = 72000,
.voltage = 0,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 108000, .domain[nv_clk_src_gpc] = 108000,
.voltage = 1,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 180000, .domain[nv_clk_src_gpc] = 180000,
.voltage = 2,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 252000, .domain[nv_clk_src_gpc] = 252000,
.voltage = 3,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 324000, .domain[nv_clk_src_gpc] = 324000,
.voltage = 4,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 396000, .domain[nv_clk_src_gpc] = 396000,
.voltage = 5,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 468000, .domain[nv_clk_src_gpc] = 468000,
.voltage = 6,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 540000, .domain[nv_clk_src_gpc] = 540000,
.voltage = 7,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 612000, .domain[nv_clk_src_gpc] = 612000,
.voltage = 8,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 648000, .domain[nv_clk_src_gpc] = 648000,
.voltage = 9,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 684000, .domain[nv_clk_src_gpc] = 684000,
.voltage = 10,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 708000, .domain[nv_clk_src_gpc] = 708000,
.voltage = 11,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 756000, .domain[nv_clk_src_gpc] = 756000,
.voltage = 12,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 804000, .domain[nv_clk_src_gpc] = 804000,
.voltage = 13,
}, },
}, },
{ {
.base = { .base = {
.domain[nv_clk_src_gpc] = 852000, .domain[nv_clk_src_gpc] = 852000,
.voltage = 14,
}, },
}, },
}; };
......
...@@ -510,7 +510,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -510,7 +510,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int ret; int ret;
ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, NULL, 0, ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, NULL, 0,
false, &priv); true, &priv);
*pobject = nv_object(priv); *pobject = nv_object(priv);
if (ret) if (ret)
return ret; return ret;
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
#include <core/option.h> #include <core/option.h>
#include <subdev/bios.h>
#include <subdev/bios/init.h>
#include <subdev/vga.h> #include <subdev/vga.h>
#include "priv.h" #include "priv.h"
...@@ -56,7 +54,7 @@ _nouveau_devinit_init(struct nouveau_object *object) ...@@ -56,7 +54,7 @@ _nouveau_devinit_init(struct nouveau_object *object)
if (ret) if (ret)
return ret; return ret;
ret = nvbios_init(&devinit->base, devinit->post); ret = impl->post(&devinit->base, devinit->post);
if (ret) if (ret)
return ret; return ret;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include "nv50.h" #include "nv50.h"
static u64 u64
gm107_devinit_disable(struct nouveau_devinit *devinit) gm107_devinit_disable(struct nouveau_devinit *devinit)
{ {
struct nv50_devinit_priv *priv = (void *)devinit; struct nv50_devinit_priv *priv = (void *)devinit;
...@@ -53,4 +53,5 @@ gm107_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -53,4 +53,5 @@ gm107_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.pll_set = nvc0_devinit_pll_set, .pll_set = nvc0_devinit_pll_set,
.disable = gm107_devinit_disable, .disable = gm107_devinit_disable,
.post = nvbios_init,
}.base; }.base;
/*
* Copyright 2013 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 <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/pmu.h>
#include "nv50.h"
static void
pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec)
{
struct nouveau_bios *bios = nouveau_bios(priv);
int i;
nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu);
for (i = 0; i < len; i += 4) {
if ((i & 0xff) == 0)
nv_wr32(priv, 0x10a188, (pmu + i) >> 8);
nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i));
}
while (i & 0xff) {
nv_wr32(priv, 0x10a184, 0x00000000);
i += 4;
}
}
static void
pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len)
{
struct nouveau_bios *bios = nouveau_bios(priv);
int i;
nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu);
for (i = 0; i < len; i += 4)
nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i));
}
static u32
pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi)
{
nv_wr32(priv, 0x10a1c0, argp);
nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi);
return nv_rd32(priv, 0x10a1c4);
}
static void
pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr)
{
nv_wr32(priv, 0x10a104, init_addr);
nv_wr32(priv, 0x10a10c, 0x00000000);
nv_wr32(priv, 0x10a100, 0x00000002);
}
static int
pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post,
u32 *init_addr_pmu, u32 *args_addr_pmu)
{
struct nouveau_bios *bios = nouveau_bios(priv);
struct nvbios_pmuR pmu;
if (!nvbios_pmuRm(bios, type, &pmu)) {
nv_error(priv, "VBIOS PMU fuc %02x not found\n", type);
return -EINVAL;
}
if (!post)
return 0;
pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false);
pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true);
pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size);
if (init_addr_pmu) {
*init_addr_pmu = pmu.init_addr_pmu;
*args_addr_pmu = pmu.args_addr_pmu;
return 0;
}
return pmu_exec(priv, pmu.init_addr_pmu), 0;
}
static int
gm204_devinit_post(struct nouveau_subdev *subdev, bool post)
{
struct nv50_devinit_priv *priv = (void *)nouveau_devinit(subdev);
struct nouveau_bios *bios = nouveau_bios(priv);
struct bit_entry bit_I;
u32 init, args;
int ret;
if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 ||
bit_I.length < 0x1c) {
nv_error(priv, "VBIOS PMU init data not found\n");
return -EINVAL;
}
/* reset PMU and load init table parser ucode */
if (post) {
nv_mask(priv, 0x000200, 0x00002000, 0x00000000);
nv_mask(priv, 0x000200, 0x00002000, 0x00002000);
nv_rd32(priv, 0x000200);
while (nv_rd32(priv, 0x10a10c) & 0x00000006) {
}
}
ret = pmu_load(priv, 0x04, post, &init, &args);
if (ret)
return ret;
/* upload first chunk of init data */
if (post) {
u32 pmu = pmu_args(priv, args + 0x08, 0x08);
u32 img = nv_ro16(bios, bit_I.offset + 0x14);
u32 len = nv_ro16(bios, bit_I.offset + 0x16);
pmu_data(priv, pmu, img, len);
}
/* upload second chunk of init data */
if (post) {
u32 pmu = pmu_args(priv, args + 0x08, 0x10);
u32 img = nv_ro16(bios, bit_I.offset + 0x18);
u32 len = nv_ro16(bios, bit_I.offset + 0x1a);
pmu_data(priv, pmu, img, len);
}
/* execute init tables */
if (post) {
nv_wr32(priv, 0x10a040, 0x00005000);
pmu_exec(priv, init);
while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) {
}
}
/* load and execute some other ucode image (bios therm?) */
return pmu_load(priv, 0x01, post, NULL, NULL);
}
struct nouveau_oclass *
gm204_devinit_oclass = &(struct nouveau_devinit_impl) {
.base.handle = NV_SUBDEV(DEVINIT, 0x07),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_devinit_ctor,
.dtor = _nouveau_devinit_dtor,
.init = nv50_devinit_init,
.fini = _nouveau_devinit_fini,
},
.pll_set = nvc0_devinit_pll_set,
.disable = gm107_devinit_disable,
.post = gm204_devinit_post,
}.base;
...@@ -464,4 +464,5 @@ nv04_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -464,4 +464,5 @@ nv04_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.meminit = nv04_devinit_meminit, .meminit = nv04_devinit_meminit,
.pll_set = nv04_devinit_pll_set, .pll_set = nv04_devinit_pll_set,
.post = nvbios_init,
}.base; }.base;
...@@ -136,4 +136,5 @@ nv05_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -136,4 +136,5 @@ nv05_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.meminit = nv05_devinit_meminit, .meminit = nv05_devinit_meminit,
.pll_set = nv04_devinit_pll_set, .pll_set = nv04_devinit_pll_set,
.post = nvbios_init,
}.base; }.base;
...@@ -107,4 +107,5 @@ nv10_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -107,4 +107,5 @@ nv10_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.meminit = nv10_devinit_meminit, .meminit = nv10_devinit_meminit,
.pll_set = nv04_devinit_pll_set, .pll_set = nv04_devinit_pll_set,
.post = nvbios_init,
}.base; }.base;
...@@ -34,4 +34,5 @@ nv1a_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -34,4 +34,5 @@ nv1a_devinit_oclass = &(struct nouveau_devinit_impl) {
.fini = nv04_devinit_fini, .fini = nv04_devinit_fini,
}, },
.pll_set = nv04_devinit_pll_set, .pll_set = nv04_devinit_pll_set,
.post = nvbios_init,
}.base; }.base;
...@@ -71,4 +71,5 @@ nv20_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -71,4 +71,5 @@ nv20_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.meminit = nv20_devinit_meminit, .meminit = nv20_devinit_meminit,
.pll_set = nv04_devinit_pll_set, .pll_set = nv04_devinit_pll_set,
.post = nvbios_init,
}.base; }.base;
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
#include <subdev/bios/disp.h> #include <subdev/bios/disp.h>
#include <subdev/bios/init.h> #include <subdev/bios/init.h>
#include <subdev/ibus.h>
#include <subdev/vga.h> #include <subdev/vga.h>
#include "nv50.h" #include "nv50.h"
...@@ -91,6 +92,7 @@ int ...@@ -91,6 +92,7 @@ int
nv50_devinit_init(struct nouveau_object *object) nv50_devinit_init(struct nouveau_object *object)
{ {
struct nouveau_bios *bios = nouveau_bios(object); struct nouveau_bios *bios = nouveau_bios(object);
struct nouveau_ibus *ibus = nouveau_ibus(object);
struct nv50_devinit_priv *priv = (void *)object; struct nv50_devinit_priv *priv = (void *)object;
struct nvbios_outp info; struct nvbios_outp info;
struct dcb_output outp; struct dcb_output outp;
...@@ -105,6 +107,13 @@ nv50_devinit_init(struct nouveau_object *object) ...@@ -105,6 +107,13 @@ nv50_devinit_init(struct nouveau_object *object)
} }
} }
/* some boards appear to require certain priv register timeouts
* to be bumped before runing devinit scripts. not a clue why
* the vbios engineers didn't make the scripts just work...
*/
if (priv->base.post && ibus)
nv_ofuncs(ibus)->init(nv_object(ibus));
ret = nouveau_devinit_init(&priv->base); ret = nouveau_devinit_init(&priv->base);
if (ret) if (ret)
return ret; return ret;
...@@ -160,4 +169,5 @@ nv50_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -160,4 +169,5 @@ nv50_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.pll_set = nv50_devinit_pll_set, .pll_set = nv50_devinit_pll_set,
.disable = nv50_devinit_disable, .disable = nv50_devinit_disable,
.post = nvbios_init,
}.base; }.base;
...@@ -18,4 +18,6 @@ int nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32); ...@@ -18,4 +18,6 @@ int nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32);
int nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32); int nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32);
u64 gm107_devinit_disable(struct nouveau_devinit *);
#endif #endif
...@@ -60,4 +60,5 @@ nv84_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -60,4 +60,5 @@ nv84_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.pll_set = nv50_devinit_pll_set, .pll_set = nv50_devinit_pll_set,
.disable = nv84_devinit_disable, .disable = nv84_devinit_disable,
.post = nvbios_init,
}.base; }.base;
...@@ -59,4 +59,5 @@ nv98_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -59,4 +59,5 @@ nv98_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.pll_set = nv50_devinit_pll_set, .pll_set = nv50_devinit_pll_set,
.disable = nv98_devinit_disable, .disable = nv98_devinit_disable,
.post = nvbios_init,
}.base; }.base;
...@@ -142,4 +142,5 @@ nva3_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -142,4 +142,5 @@ nva3_devinit_oclass = &(struct nouveau_devinit_impl) {
.pll_set = nva3_devinit_pll_set, .pll_set = nva3_devinit_pll_set,
.disable = nva3_devinit_disable, .disable = nva3_devinit_disable,
.mmio = nva3_devinit_mmio, .mmio = nva3_devinit_mmio,
.post = nvbios_init,
}.base; }.base;
...@@ -60,4 +60,5 @@ nvaf_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -60,4 +60,5 @@ nvaf_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.pll_set = nva3_devinit_pll_set, .pll_set = nva3_devinit_pll_set,
.disable = nvaf_devinit_disable, .disable = nvaf_devinit_disable,
.post = nvbios_init,
}.base; }.base;
...@@ -115,4 +115,5 @@ nvc0_devinit_oclass = &(struct nouveau_devinit_impl) { ...@@ -115,4 +115,5 @@ nvc0_devinit_oclass = &(struct nouveau_devinit_impl) {
}, },
.pll_set = nvc0_devinit_pll_set, .pll_set = nvc0_devinit_pll_set,
.disable = nvc0_devinit_disable, .disable = nvc0_devinit_disable,
.post = nvbios_init,
}.base; }.base;
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/pll.h> #include <subdev/bios/pll.h>
#include <subdev/bios/init.h>
#include <subdev/clock/pll.h> #include <subdev/clock/pll.h>
#include <subdev/devinit.h> #include <subdev/devinit.h>
...@@ -12,6 +13,7 @@ struct nouveau_devinit_impl { ...@@ -12,6 +13,7 @@ struct nouveau_devinit_impl {
int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq); int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
u64 (*disable)(struct nouveau_devinit *); u64 (*disable)(struct nouveau_devinit *);
u32 (*mmio)(struct nouveau_devinit *, u32); u32 (*mmio)(struct nouveau_devinit *, u32);
int (*post)(struct nouveau_subdev *, bool);
}; };
#define nouveau_devinit_create(p,e,o,d) \ #define nouveau_devinit_create(p,e,o,d) \
......
...@@ -23,37 +23,30 @@ ...@@ -23,37 +23,30 @@
*/ */
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/bit.h> #include <subdev/bios/M0203.h>
#include "priv.h" #include "priv.h"
int int
nouveau_fb_bios_memtype(struct nouveau_bios *bios) nouveau_fb_bios_memtype(struct nouveau_bios *bios)
{ {
struct bit_entry M; const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
u8 ramcfg; struct nvbios_M0203E M0203E;
u8 ver, hdr;
ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
if (!bit_entry(bios, 'M', &M) && M.version == 2 && M.length >= 5) { if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
u16 table = nv_ro16(bios, M.offset + 3); switch (M0203E.type) {
u8 version = nv_ro08(bios, table + 0); case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2;
u8 header = nv_ro08(bios, table + 1); case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3;
u8 record = nv_ro08(bios, table + 2); case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3;
u8 entries = nv_ro08(bios, table + 3); case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5;
if (table && version == 0x10 && ramcfg < entries) {
u16 entry = table + header + (ramcfg * record);
switch (nv_ro08(bios, entry) & 0x0f) {
case 0: return NV_MEM_TYPE_DDR2;
case 1: return NV_MEM_TYPE_DDR3;
case 2: return NV_MEM_TYPE_GDDR3;
case 3: return NV_MEM_TYPE_GDDR5;
default: default:
break; nv_warn(bios, "M0203E type %02x\n", M0203E.type);
} return NV_MEM_TYPE_UNKNOWN;
} }
} }
nv_warn(bios, "M0203E not matched!\n");
return NV_MEM_TYPE_UNKNOWN; return NV_MEM_TYPE_UNKNOWN;
} }
......
/*
* Copyright 2013 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>
* Roy Spliet <rspliet@eclipso.eu>
*/
#include <subdev/bios.h>
#include "priv.h"
struct ramxlat {
int id;
u8 enc;
};
static inline int
ramxlat(const struct ramxlat *xlat, int id)
{
while (xlat->id >= 0) {
if (xlat->id == id)
return xlat->enc;
xlat++;
}
return -EINVAL;
}
static const struct ramxlat
ramgddr3_cl_lo[] = {
{ 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 },
/* the below are mentioned in some, but not all, gddr3 docs */
{ 12, 4 }, { 13, 5 }, { 14, 6 },
/* XXX: Per Samsung docs, are these used? They overlap with Qimonda */
/* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 },
* { 15, 11 }, */
{ -1 }
};
static const struct ramxlat
ramgddr3_cl_hi[] = {
{ 10, 2 }, { 11, 3 }, { 12, 4 }, { 13, 5 }, { 14, 6 }, { 15, 7 },
{ 16, 0 }, { 17, 1 },
{ -1 }
};
static const struct ramxlat
ramgddr3_wr_lo[] = {
{ 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 },
{ 11, 0 },
/* the below are mentioned in some, but not all, gddr3 docs */
{ 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 },
{ -1 }
};
int
nouveau_gddr3_calc(struct nouveau_ram *ram)
{
int CL, WR, CWL, DLL = 0, ODT = 0, hi;
switch (ram->next->bios.timing_ver) {
case 0x10:
CWL = ram->next->bios.timing_10_CWL;
CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR;
DLL = !ram->next->bios.ramcfg_10_DLLoff;
ODT = ram->next->bios.timing_10_ODT;
break;
case 0x20:
CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
/* XXX: Get these values from the VBIOS instead */
DLL = !(ram->mr[1] & 0x1);
ODT = (ram->mr[1] & 0x004) >> 2 |
(ram->mr[1] & 0x040) >> 5 |
(ram->mr[1] & 0x200) >> 7;
break;
default:
return -ENOSYS;
}
hi = ram->mr[2] & 0x1;
CL = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL);
WR = ramxlat(ramgddr3_wr_lo, WR);
if (CL < 0 || CWL < 1 || CWL > 7 || WR < 0)
return -EINVAL;
ram->mr[0] &= ~0xf74;
ram->mr[0] |= (CWL & 0x07) << 9;
ram->mr[0] |= (CL & 0x07) << 4;
ram->mr[0] |= (CL & 0x08) >> 1;
ram->mr[1] &= ~0x3fc;
ram->mr[1] |= (ODT & 0x03) << 2;
ram->mr[1] |= (ODT & 0x03) << 8;
ram->mr[1] |= (WR & 0x03) << 4;
ram->mr[1] |= (WR & 0x04) << 5;
ram->mr[1] |= !DLL << 6;
return 0;
}
...@@ -37,6 +37,7 @@ extern struct nouveau_oclass gm107_ram_oclass; ...@@ -37,6 +37,7 @@ extern struct nouveau_oclass gm107_ram_oclass;
int nouveau_sddr2_calc(struct nouveau_ram *ram); int nouveau_sddr2_calc(struct nouveau_ram *ram);
int nouveau_sddr3_calc(struct nouveau_ram *ram); int nouveau_sddr3_calc(struct nouveau_ram *ram);
int nouveau_gddr3_calc(struct nouveau_ram *ram);
int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts); int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
#define nouveau_fb_create(p,e,c,d) \ #define nouveau_fb_create(p,e,c,d) \
......
...@@ -140,6 +140,20 @@ ramfuc_wait_vblank(struct ramfuc *ram) ...@@ -140,6 +140,20 @@ ramfuc_wait_vblank(struct ramfuc *ram)
nouveau_memx_wait_vblank(ram->memx); nouveau_memx_wait_vblank(ram->memx);
} }
static inline void
ramfuc_train(struct ramfuc *ram)
{
nouveau_memx_train(ram->memx);
}
static inline int
ramfuc_train_result(struct nouveau_fb *pfb, u32 *result, u32 rsize)
{
struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
return nouveau_memx_train_result(ppwr, result, rsize);
}
static inline void static inline void
ramfuc_block(struct ramfuc *ram) ramfuc_block(struct ramfuc *ram)
{ {
...@@ -162,6 +176,8 @@ ramfuc_unblock(struct ramfuc *ram) ...@@ -162,6 +176,8 @@ ramfuc_unblock(struct ramfuc *ram)
#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n)) #define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n)) #define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n))
#define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base) #define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base)
#define ram_train(s) ramfuc_train(&(s)->base)
#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
#define ram_block(s) ramfuc_block(&(s)->base) #define ram_block(s) ramfuc_block(&(s)->base)
#define ram_unblock(s) ramfuc_unblock(&(s)->base) #define ram_unblock(s) ramfuc_unblock(&(s)->base)
......
...@@ -66,7 +66,7 @@ nouveau_sddr2_calc(struct nouveau_ram *ram) ...@@ -66,7 +66,7 @@ nouveau_sddr2_calc(struct nouveau_ram *ram)
case 0x10: case 0x10:
CL = ram->next->bios.timing_10_CL; CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR; WR = ram->next->bios.timing_10_WR;
DLL = !ram->next->bios.ramcfg_10_02_40; DLL = !ram->next->bios.ramcfg_10_DLLoff;
ODT = ram->next->bios.timing_10_ODT & 3; ODT = ram->next->bios.timing_10_ODT & 3;
break; break;
case 0x20: case 0x20:
......
...@@ -80,7 +80,7 @@ nouveau_sddr3_calc(struct nouveau_ram *ram) ...@@ -80,7 +80,7 @@ nouveau_sddr3_calc(struct nouveau_ram *ram)
CWL = ram->next->bios.timing_10_CWL; CWL = ram->next->bios.timing_10_CWL;
CL = ram->next->bios.timing_10_CL; CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR; WR = ram->next->bios.timing_10_WR;
DLL = !ram->next->bios.ramcfg_10_02_40; DLL = !ram->next->bios.ramcfg_10_DLLoff;
ODT = ram->next->bios.timing_10_ODT; ODT = ram->next->bios.timing_10_ODT;
break; break;
case 0x20: case 0x20:
......
...@@ -54,7 +54,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) ...@@ -54,7 +54,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
} }
} }
static int int
nv50_gpio_location(int line, u32 *reg, u32 *shift) nv50_gpio_location(int line, u32 *reg, u32 *shift)
{ {
const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
......
...@@ -473,18 +473,56 @@ nouveau_i2c_extdev_sclass[] = { ...@@ -473,18 +473,56 @@ nouveau_i2c_extdev_sclass[] = {
nouveau_anx9805_sclass, nouveau_anx9805_sclass,
}; };
static void
nouveau_i2c_create_port(struct nouveau_i2c *i2c, int index, u8 type,
struct dcb_i2c_entry *info)
{
const struct nouveau_i2c_impl *impl = (void *)nv_oclass(i2c);
struct nouveau_oclass *oclass;
struct nouveau_object *parent;
struct nouveau_object *object;
int ret, pad;
if (info->share != DCB_I2C_UNUSED) {
pad = info->share;
oclass = impl->pad_s;
} else {
if (type != DCB_I2C_NVIO_AUX)
pad = 0x100 + info->drive;
else
pad = 0x100 + info->auxch;
oclass = impl->pad_x;
}
ret = nouveau_object_ctor(NULL, nv_object(i2c), oclass, NULL, pad,
&parent);
if (ret < 0)
return;
oclass = impl->sclass;
do {
ret = -EINVAL;
if (oclass->handle == type) {
ret = nouveau_object_ctor(parent, nv_object(i2c),
oclass, info, index,
&object);
}
} while (ret && (++oclass)->handle);
nouveau_object_ref(NULL, &parent);
}
int int
nouveau_i2c_create_(struct nouveau_object *parent, nouveau_i2c_create_(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, struct nouveau_oclass *oclass,
int length, void **pobject) int length, void **pobject)
{ {
const struct nouveau_i2c_impl *impl = (void *)oclass;
struct nouveau_bios *bios = nouveau_bios(parent); struct nouveau_bios *bios = nouveau_bios(parent);
struct nouveau_i2c *i2c; struct nouveau_i2c *i2c;
struct nouveau_object *object; struct nouveau_object *object;
struct dcb_i2c_entry info; struct dcb_i2c_entry info;
int ret, i, j, index = -1, pad; int ret, i, j, index = -1;
struct dcb_output outp; struct dcb_output outp;
u8 ver, hdr; u8 ver, hdr;
u32 data; u32 data;
...@@ -507,43 +545,40 @@ nouveau_i2c_create_(struct nouveau_object *parent, ...@@ -507,43 +545,40 @@ nouveau_i2c_create_(struct nouveau_object *parent,
INIT_LIST_HEAD(&i2c->ports); INIT_LIST_HEAD(&i2c->ports);
while (!dcb_i2c_parse(bios, ++index, &info)) { while (!dcb_i2c_parse(bios, ++index, &info)) {
if (info.type == DCB_I2C_UNUSED) switch (info.type) {
continue; case DCB_I2C_NV04_BIT:
case DCB_I2C_NV4E_BIT:
if (info.share != DCB_I2C_UNUSED) { case DCB_I2C_NVIO_BIT:
if (info.type == DCB_I2C_NVIO_AUX) nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
pad = info.drive; info.type, &info);
else break;
pad = info.share; case DCB_I2C_NVIO_AUX:
oclass = impl->pad_s; nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
} else { info.type, &info);
pad = 0x100 + info.drive; break;
oclass = impl->pad_x; case DCB_I2C_PMGR:
if (info.drive != DCB_I2C_UNUSED) {
nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
DCB_I2C_NVIO_BIT,
&info);
} }
if (info.auxch != DCB_I2C_UNUSED) {
ret = nouveau_object_ctor(NULL, *pobject, oclass, nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
NULL, pad, &parent); DCB_I2C_NVIO_AUX,
if (ret < 0) &info);
}
break;
case DCB_I2C_UNUSED:
default:
continue; continue;
oclass = impl->sclass;
do {
ret = -EINVAL;
if (oclass->handle == info.type) {
ret = nouveau_object_ctor(parent, *pobject,
oclass, &info,
index, &object);
} }
} while (ret && (++oclass)->handle);
nouveau_object_ref(NULL, &parent);
} }
/* in addition to the busses specified in the i2c table, there /* in addition to the busses specified in the i2c table, there
* may be ddc/aux channels hiding behind external tmds/dp/etc * may be ddc/aux channels hiding behind external tmds/dp/etc
* transmitters. * transmitters.
*/ */
index = ((index + 0x0f) / 0x10) * 0x10; index = NV_I2C_EXT(0);
i = -1; i = -1;
while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) { while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
if (!outp.location || !outp.extdev) if (!outp.location || !outp.extdev)
......
/*
* 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 "nv50.h"
#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
static void
auxch_fini(struct nouveau_i2c *aux, int ch)
{
nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000);
}
static int
auxch_init(struct nouveau_i2c *aux, int ch)
{
const u32 unksel = 1; /* nfi which to use, or if it matters.. */
const u32 ureq = unksel ? 0x00100000 : 0x00200000;
const u32 urep = unksel ? 0x01000000 : 0x02000000;
u32 ctrl, timeout;
/* wait up to 1ms for any previous transaction to be done... */
timeout = 1000;
do {
ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
udelay(1);
if (!timeout--) {
AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
return -EBUSY;
}
} while (ctrl & 0x03010000);
/* set some magic, and wait up to 1ms for it to appear */
nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq);
timeout = 1000;
do {
ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
udelay(1);
if (!timeout--) {
AUX_ERR("magic wait 0x%08x\n", ctrl);
auxch_fini(aux, ch);
return -EBUSY;
}
} while ((ctrl & 0x03000000) != urep);
return 0;
}
int
gm204_aux(struct nouveau_i2c_port *base, bool retry,
u8 type, u32 addr, u8 *data, u8 size)
{
struct nouveau_i2c *aux = nouveau_i2c(base);
struct nv50_i2c_port *port = (void *)base;
u32 ctrl, stat, timeout, retries;
u32 xbuf[4] = {};
int ch = port->addr;
int ret, i;
AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
ret = auxch_init(aux, ch);
if (ret)
goto out;
stat = nv_rd32(aux, 0x00d958 + (ch * 0x50));
if (!(stat & 0x10000000)) {
AUX_DBG("sink not detected\n");
ret = -ENXIO;
goto out;
}
if (!(type & 1)) {
memcpy(xbuf, data, size);
for (i = 0; i < 16; i += 4) {
AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]);
}
}
ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
ctrl &= ~0x0001f0ff;
ctrl |= type << 12;
ctrl |= size - 1;
nv_wr32(aux, 0x00d950 + (ch * 0x50), addr);
/* (maybe) retry transaction a number of times on failure... */
for (retries = 0; !ret && retries < 32; retries++) {
/* reset, and delay a while if this is a retry */
nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl);
nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl);
if (retries)
udelay(400);
/* transaction request, wait up to 1ms for it to complete */
nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl);
timeout = 1000;
do {
ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
udelay(1);
if (!timeout--) {
AUX_ERR("tx req timeout 0x%08x\n", ctrl);
ret = -EIO;
goto out;
}
} while (ctrl & 0x00010000);
ret = 1;
/* read status, and check if transaction completed ok */
stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0);
if ((stat & 0x000f0000) == 0x00080000 ||
(stat & 0x000f0000) == 0x00020000)
ret = retry ? 0 : 1;
if ((stat & 0x00000100))
ret = -ETIMEDOUT;
if ((stat & 0x00000e00))
ret = -EIO;
AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
}
if (type & 1) {
for (i = 0; i < 16; i += 4) {
xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i);
AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
}
memcpy(data, xbuf, size);
}
out:
auxch_fini(aux, ch);
return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
}
static const struct nouveau_i2c_func
gm204_aux_func = {
.aux = gm204_aux,
};
int
gm204_aux_port_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 index,
struct nouveau_object **pobject)
{
struct dcb_i2c_entry *info = data;
struct nv50_i2c_port *port;
int ret;
ret = nouveau_i2c_port_create(parent, engine, oclass, index,
&nouveau_i2c_aux_algo, &gm204_aux_func,
&port);
*pobject = nv_object(port);
if (ret)
return ret;
port->base.aux = info->auxch;
port->addr = info->auxch;
return 0;
}
struct nouveau_oclass
gm204_i2c_sclass[] = {
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvd0_i2c_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = nv50_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = gm204_aux_port_ctor,
.dtor = _nouveau_i2c_port_dtor,
.init = _nouveau_i2c_port_init,
.fini = _nouveau_i2c_port_fini,
},
},
{}
};
struct nouveau_oclass *
gm204_i2c_oclass = &(struct nouveau_i2c_impl) {
.base.handle = NV_SUBDEV(I2C, 0x24),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_i2c_ctor,
.dtor = _nouveau_i2c_dtor,
.init = _nouveau_i2c_init,
.fini = _nouveau_i2c_fini,
},
.sclass = gm204_i2c_sclass,
.pad_x = &nv04_i2c_pad_oclass,
.pad_s = &gm204_i2c_pad_oclass,
.aux = 8,
.aux_stat = nve0_aux_stat,
.aux_mask = nve0_aux_mask,
}.base;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment