提交 bc1dfff0 编写于 作者: D Dave Airlie

Merge branch 'drm-nouveau-next' of...

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

display rework fixes lots of displayport issues.

* 'drm-nouveau-next' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (43 commits)
  drm/nouveau/disp/dp: fix tmds passthrough on dp connector
  drm/nouveau/dp: probe dpcd to determine connectedness
  drm/nv50-: trigger update after all connectors disabled
  drm/nv50-: prepare for attaching a SOR to multiple heads
  drm/gf119-/disp: fix debug output on update failure
  drm/nouveau/disp/dp: make use of postcursor when its available
  drm/g94-/disp/dp: take max pullup value across all lanes
  drm/nouveau/bios/dp: parse lane postcursor data
  drm/nouveau/dp: fix support for dpms
  drm/nouveau: register a drm_dp_aux channel for each dp connector
  drm/g94-/disp: add method to power-off dp lanes
  drm/nouveau/disp/dp: maintain link in response to hpd signal
  drm/g94-/disp: bash and wait for something after changing lane power regs
  drm/nouveau/disp/dp: split link config/power into two steps
  drm/nv50/disp: train PIOR-attached DP from second supervisor
  drm/nouveau/disp/dp: make use of existing output data for link training
  drm/gf119/disp: start removing direct vbios parsing from supervisor
  drm/nv50/disp: start removing direct vbios parsing from supervisor
  drm/nouveau/disp/dp: maintain receiver caps in response to hpd signal
  drm/nouveau/disp/dp: create subclass for dp outputs
  ...
...@@ -125,17 +125,22 @@ nouveau-y += core/subdev/fb/gddr5.o ...@@ -125,17 +125,22 @@ nouveau-y += core/subdev/fb/gddr5.o
nouveau-y += core/subdev/gpio/base.o nouveau-y += core/subdev/gpio/base.o
nouveau-y += core/subdev/gpio/nv10.o nouveau-y += core/subdev/gpio/nv10.o
nouveau-y += core/subdev/gpio/nv50.o nouveau-y += core/subdev/gpio/nv50.o
nouveau-y += core/subdev/gpio/nv92.o
nouveau-y += core/subdev/gpio/nvd0.o nouveau-y += core/subdev/gpio/nvd0.o
nouveau-y += core/subdev/gpio/nve0.o nouveau-y += core/subdev/gpio/nve0.o
nouveau-y += core/subdev/i2c/base.o nouveau-y += core/subdev/i2c/base.o
nouveau-y += core/subdev/i2c/anx9805.o nouveau-y += core/subdev/i2c/anx9805.o
nouveau-y += core/subdev/i2c/aux.o nouveau-y += core/subdev/i2c/aux.o
nouveau-y += core/subdev/i2c/bit.o nouveau-y += core/subdev/i2c/bit.o
nouveau-y += core/subdev/i2c/pad.o
nouveau-y += core/subdev/i2c/padnv04.o
nouveau-y += core/subdev/i2c/padnv94.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
nouveau-y += core/subdev/i2c/nv94.o 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/nve0.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
...@@ -217,6 +222,9 @@ nouveau-y += core/engine/device/nvc0.o ...@@ -217,6 +222,9 @@ nouveau-y += core/engine/device/nvc0.o
nouveau-y += core/engine/device/nve0.o nouveau-y += core/engine/device/nve0.o
nouveau-y += core/engine/device/gm100.o nouveau-y += core/engine/device/gm100.o
nouveau-y += core/engine/disp/base.o nouveau-y += core/engine/disp/base.o
nouveau-y += core/engine/disp/conn.o
nouveau-y += core/engine/disp/outp.o
nouveau-y += core/engine/disp/outpdp.o
nouveau-y += core/engine/disp/nv04.o nouveau-y += core/engine/disp/nv04.o
nouveau-y += core/engine/disp/nv50.o nouveau-y += core/engine/disp/nv50.o
nouveau-y += core/engine/disp/nv84.o nouveau-y += core/engine/disp/nv84.o
......
...@@ -28,14 +28,20 @@ nouveau_event_put(struct nouveau_eventh *handler) ...@@ -28,14 +28,20 @@ nouveau_event_put(struct nouveau_eventh *handler)
{ {
struct nouveau_event *event = handler->event; struct nouveau_event *event = handler->event;
unsigned long flags; unsigned long flags;
if (__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags)) { u32 m, t;
spin_lock_irqsave(&event->refs_lock, flags);
if (!--event->index[handler->index].refs) { if (!__test_and_clear_bit(NVKM_EVENT_ENABLE, &handler->flags))
return;
spin_lock_irqsave(&event->refs_lock, flags);
for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
if (!--event->refs[handler->index * event->types_nr + t]) {
if (event->disable) if (event->disable)
event->disable(event, handler->index); event->disable(event, 1 << t, handler->index);
} }
spin_unlock_irqrestore(&event->refs_lock, flags);
} }
spin_unlock_irqrestore(&event->refs_lock, flags);
} }
void void
...@@ -43,14 +49,20 @@ nouveau_event_get(struct nouveau_eventh *handler) ...@@ -43,14 +49,20 @@ nouveau_event_get(struct nouveau_eventh *handler)
{ {
struct nouveau_event *event = handler->event; struct nouveau_event *event = handler->event;
unsigned long flags; unsigned long flags;
if (!__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags)) { u32 m, t;
spin_lock_irqsave(&event->refs_lock, flags);
if (!event->index[handler->index].refs++) { if (__test_and_set_bit(NVKM_EVENT_ENABLE, &handler->flags))
return;
spin_lock_irqsave(&event->refs_lock, flags);
for (m = handler->types; t = __ffs(m), m; m &= ~(1 << t)) {
if (!event->refs[handler->index * event->types_nr + t]++) {
if (event->enable) if (event->enable)
event->enable(event, handler->index); event->enable(event, 1 << t, handler->index);
} }
spin_unlock_irqrestore(&event->refs_lock, flags);
} }
spin_unlock_irqrestore(&event->refs_lock, flags);
} }
static void static void
...@@ -65,38 +77,47 @@ nouveau_event_fini(struct nouveau_eventh *handler) ...@@ -65,38 +77,47 @@ nouveau_event_fini(struct nouveau_eventh *handler)
} }
static int static int
nouveau_event_init(struct nouveau_event *event, int index, nouveau_event_init(struct nouveau_event *event, u32 types, int index,
int (*func)(void *, int), void *priv, int (*func)(void *, u32, int), void *priv,
struct nouveau_eventh *handler) struct nouveau_eventh *handler)
{ {
unsigned long flags; unsigned long flags;
if (types & ~((1 << event->types_nr) - 1))
return -EINVAL;
if (index >= event->index_nr) if (index >= event->index_nr)
return -EINVAL; return -EINVAL;
handler->event = event; handler->event = event;
handler->flags = 0; handler->flags = 0;
handler->types = types;
handler->index = index; handler->index = index;
handler->func = func; handler->func = func;
handler->priv = priv; handler->priv = priv;
spin_lock_irqsave(&event->list_lock, flags); spin_lock_irqsave(&event->list_lock, flags);
list_add_tail(&handler->head, &event->index[index].list); list_add_tail(&handler->head, &event->list[index]);
spin_unlock_irqrestore(&event->list_lock, flags); spin_unlock_irqrestore(&event->list_lock, flags);
return 0; return 0;
} }
int int
nouveau_event_new(struct nouveau_event *event, int index, nouveau_event_new(struct nouveau_event *event, u32 types, int index,
int (*func)(void *, int), void *priv, int (*func)(void *, u32, int), void *priv,
struct nouveau_eventh **phandler) struct nouveau_eventh **phandler)
{ {
struct nouveau_eventh *handler; struct nouveau_eventh *handler;
int ret = -ENOMEM; int ret = -ENOMEM;
if (event->check) {
ret = event->check(event, types, index);
if (ret)
return ret;
}
handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL); handler = *phandler = kmalloc(sizeof(*handler), GFP_KERNEL);
if (handler) { if (handler) {
ret = nouveau_event_init(event, index, func, priv, handler); ret = nouveau_event_init(event, types, index, func, priv, handler);
if (ret) if (ret)
kfree(handler); kfree(handler);
} }
...@@ -116,7 +137,7 @@ nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref) ...@@ -116,7 +137,7 @@ nouveau_event_ref(struct nouveau_eventh *handler, struct nouveau_eventh **ref)
} }
void void
nouveau_event_trigger(struct nouveau_event *event, int index) nouveau_event_trigger(struct nouveau_event *event, u32 types, int index)
{ {
struct nouveau_eventh *handler; struct nouveau_eventh *handler;
unsigned long flags; unsigned long flags;
...@@ -125,10 +146,15 @@ nouveau_event_trigger(struct nouveau_event *event, int index) ...@@ -125,10 +146,15 @@ nouveau_event_trigger(struct nouveau_event *event, int index)
return; return;
spin_lock_irqsave(&event->list_lock, flags); spin_lock_irqsave(&event->list_lock, flags);
list_for_each_entry(handler, &event->index[index].list, head) { list_for_each_entry(handler, &event->list[index], head) {
if (test_bit(NVKM_EVENT_ENABLE, &handler->flags) && if (!test_bit(NVKM_EVENT_ENABLE, &handler->flags))
handler->func(handler->priv, index) == NVKM_EVENT_DROP) continue;
nouveau_event_put(handler); if (!(handler->types & types))
continue;
if (handler->func(handler->priv, handler->types & types, index)
!= NVKM_EVENT_DROP)
continue;
nouveau_event_put(handler);
} }
spin_unlock_irqrestore(&event->list_lock, flags); spin_unlock_irqrestore(&event->list_lock, flags);
} }
...@@ -144,20 +170,27 @@ nouveau_event_destroy(struct nouveau_event **pevent) ...@@ -144,20 +170,27 @@ nouveau_event_destroy(struct nouveau_event **pevent)
} }
int int
nouveau_event_create(int index_nr, struct nouveau_event **pevent) nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **pevent)
{ {
struct nouveau_event *event; struct nouveau_event *event;
int i; int i;
event = *pevent = kzalloc(sizeof(*event) + index_nr * event = *pevent = kzalloc(sizeof(*event) + (index_nr * types_nr) *
sizeof(event->index[0]), GFP_KERNEL); sizeof(event->refs[0]), GFP_KERNEL);
if (!event) if (!event)
return -ENOMEM; return -ENOMEM;
event->list = kmalloc(sizeof(*event->list) * index_nr, GFP_KERNEL);
if (!event->list) {
kfree(event);
return -ENOMEM;
}
spin_lock_init(&event->list_lock); spin_lock_init(&event->list_lock);
spin_lock_init(&event->refs_lock); spin_lock_init(&event->refs_lock);
for (i = 0; i < index_nr; i++) for (i = 0; i < index_nr; i++)
INIT_LIST_HEAD(&event->index[i].list); INIT_LIST_HEAD(&event->list[i]);
event->types_nr = types_nr;
event->index_nr = index_nr; event->index_nr = index_nr;
return 0; return 0;
} }
...@@ -60,8 +60,8 @@ gm100_identify(struct nouveau_device *device) ...@@ -60,8 +60,8 @@ gm100_identify(struct nouveau_device *device)
case 0x117: case 0x117:
device->cname = "GM107"; device->cname = "GM107";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
#if 0 #if 0
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
......
...@@ -47,7 +47,7 @@ nv04_identify(struct nouveau_device *device) ...@@ -47,7 +47,7 @@ nv04_identify(struct nouveau_device *device)
case 0x04: case 0x04:
device->cname = "NV04"; device->cname = "NV04";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -65,7 +65,7 @@ nv04_identify(struct nouveau_device *device) ...@@ -65,7 +65,7 @@ nv04_identify(struct nouveau_device *device)
case 0x05: case 0x05:
device->cname = "NV05"; device->cname = "NV05";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
......
...@@ -48,8 +48,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -48,8 +48,8 @@ nv10_identify(struct nouveau_device *device)
case 0x10: case 0x10:
device->cname = "NV10"; device->cname = "NV10";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -65,8 +65,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -65,8 +65,8 @@ nv10_identify(struct nouveau_device *device)
case 0x15: case 0x15:
device->cname = "NV15"; device->cname = "NV15";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -84,8 +84,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -84,8 +84,8 @@ nv10_identify(struct nouveau_device *device)
case 0x16: case 0x16:
device->cname = "NV16"; device->cname = "NV16";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -103,8 +103,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -103,8 +103,8 @@ nv10_identify(struct nouveau_device *device)
case 0x1a: case 0x1a:
device->cname = "nForce"; device->cname = "nForce";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -122,8 +122,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -122,8 +122,8 @@ nv10_identify(struct nouveau_device *device)
case 0x11: case 0x11:
device->cname = "NV11"; device->cname = "NV11";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -141,8 +141,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -141,8 +141,8 @@ nv10_identify(struct nouveau_device *device)
case 0x17: case 0x17:
device->cname = "NV17"; device->cname = "NV17";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -160,8 +160,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -160,8 +160,8 @@ nv10_identify(struct nouveau_device *device)
case 0x1f: case 0x1f:
device->cname = "nForce2"; device->cname = "nForce2";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -179,8 +179,8 @@ nv10_identify(struct nouveau_device *device) ...@@ -179,8 +179,8 @@ nv10_identify(struct nouveau_device *device)
case 0x18: case 0x18:
device->cname = "NV18"; device->cname = "NV18";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
......
...@@ -49,8 +49,8 @@ nv20_identify(struct nouveau_device *device) ...@@ -49,8 +49,8 @@ nv20_identify(struct nouveau_device *device)
case 0x20: case 0x20:
device->cname = "NV20"; device->cname = "NV20";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -68,8 +68,8 @@ nv20_identify(struct nouveau_device *device) ...@@ -68,8 +68,8 @@ nv20_identify(struct nouveau_device *device)
case 0x25: case 0x25:
device->cname = "NV25"; device->cname = "NV25";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -87,8 +87,8 @@ nv20_identify(struct nouveau_device *device) ...@@ -87,8 +87,8 @@ nv20_identify(struct nouveau_device *device)
case 0x28: case 0x28:
device->cname = "NV28"; device->cname = "NV28";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -106,8 +106,8 @@ nv20_identify(struct nouveau_device *device) ...@@ -106,8 +106,8 @@ nv20_identify(struct nouveau_device *device)
case 0x2a: case 0x2a:
device->cname = "NV2A"; device->cname = "NV2A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
......
...@@ -49,8 +49,8 @@ nv30_identify(struct nouveau_device *device) ...@@ -49,8 +49,8 @@ nv30_identify(struct nouveau_device *device)
case 0x30: case 0x30:
device->cname = "NV30"; device->cname = "NV30";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -68,8 +68,8 @@ nv30_identify(struct nouveau_device *device) ...@@ -68,8 +68,8 @@ nv30_identify(struct nouveau_device *device)
case 0x35: case 0x35:
device->cname = "NV35"; device->cname = "NV35";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -87,8 +87,8 @@ nv30_identify(struct nouveau_device *device) ...@@ -87,8 +87,8 @@ nv30_identify(struct nouveau_device *device)
case 0x31: case 0x31:
device->cname = "NV31"; device->cname = "NV31";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -107,8 +107,8 @@ nv30_identify(struct nouveau_device *device) ...@@ -107,8 +107,8 @@ nv30_identify(struct nouveau_device *device)
case 0x36: case 0x36:
device->cname = "NV36"; device->cname = "NV36";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
...@@ -127,8 +127,8 @@ nv30_identify(struct nouveau_device *device) ...@@ -127,8 +127,8 @@ nv30_identify(struct nouveau_device *device)
case 0x34: case 0x34:
device->cname = "NV34"; device->cname = "NV34";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
......
...@@ -53,8 +53,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -53,8 +53,8 @@ nv40_identify(struct nouveau_device *device)
case 0x40: case 0x40:
device->cname = "NV40"; device->cname = "NV40";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -76,8 +76,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -76,8 +76,8 @@ nv40_identify(struct nouveau_device *device)
case 0x41: case 0x41:
device->cname = "NV41"; device->cname = "NV41";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -99,8 +99,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -99,8 +99,8 @@ nv40_identify(struct nouveau_device *device)
case 0x42: case 0x42:
device->cname = "NV42"; device->cname = "NV42";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -122,8 +122,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -122,8 +122,8 @@ nv40_identify(struct nouveau_device *device)
case 0x43: case 0x43:
device->cname = "NV43"; device->cname = "NV43";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -145,8 +145,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -145,8 +145,8 @@ nv40_identify(struct nouveau_device *device)
case 0x45: case 0x45:
device->cname = "NV45"; device->cname = "NV45";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -168,8 +168,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -168,8 +168,8 @@ nv40_identify(struct nouveau_device *device)
case 0x47: case 0x47:
device->cname = "G70"; device->cname = "G70";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -191,8 +191,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -191,8 +191,8 @@ nv40_identify(struct nouveau_device *device)
case 0x49: case 0x49:
device->cname = "G71"; device->cname = "G71";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -214,8 +214,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -214,8 +214,8 @@ nv40_identify(struct nouveau_device *device)
case 0x4b: case 0x4b:
device->cname = "G73"; device->cname = "G73";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -237,8 +237,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -237,8 +237,8 @@ nv40_identify(struct nouveau_device *device)
case 0x44: case 0x44:
device->cname = "NV44"; device->cname = "NV44";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -260,8 +260,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -260,8 +260,8 @@ nv40_identify(struct nouveau_device *device)
case 0x46: case 0x46:
device->cname = "G72"; device->cname = "G72";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -283,8 +283,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -283,8 +283,8 @@ nv40_identify(struct nouveau_device *device)
case 0x4a: case 0x4a:
device->cname = "NV44A"; device->cname = "NV44A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -306,8 +306,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -306,8 +306,8 @@ nv40_identify(struct nouveau_device *device)
case 0x4c: case 0x4c:
device->cname = "C61"; device->cname = "C61";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -329,8 +329,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -329,8 +329,8 @@ nv40_identify(struct nouveau_device *device)
case 0x4e: case 0x4e:
device->cname = "C51"; device->cname = "C51";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv4e_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -352,8 +352,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -352,8 +352,8 @@ nv40_identify(struct nouveau_device *device)
case 0x63: case 0x63:
device->cname = "C73"; device->cname = "C73";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -375,8 +375,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -375,8 +375,8 @@ nv40_identify(struct nouveau_device *device)
case 0x67: case 0x67:
device->cname = "C67"; device->cname = "C67";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
...@@ -398,8 +398,8 @@ nv40_identify(struct nouveau_device *device) ...@@ -398,8 +398,8 @@ nv40_identify(struct nouveau_device *device)
case 0x68: case 0x68:
device->cname = "C68"; device->cname = "C68";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
......
...@@ -60,8 +60,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -60,8 +60,8 @@ nv50_identify(struct nouveau_device *device)
case 0x50: case 0x50:
device->cname = "G80"; device->cname = "G80";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -85,8 +85,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -85,8 +85,8 @@ nv50_identify(struct nouveau_device *device)
case 0x84: case 0x84:
device->cname = "G84"; device->cname = "G84";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -113,8 +113,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -113,8 +113,8 @@ nv50_identify(struct nouveau_device *device)
case 0x86: case 0x86:
device->cname = "G86"; device->cname = "G86";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -141,8 +141,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -141,8 +141,8 @@ nv50_identify(struct nouveau_device *device)
case 0x92: case 0x92:
device->cname = "G92"; device->cname = "G92";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -169,8 +169,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -169,8 +169,8 @@ nv50_identify(struct nouveau_device *device)
case 0x94: case 0x94:
device->cname = "G94"; device->cname = "G94";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -197,8 +197,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -197,8 +197,8 @@ nv50_identify(struct nouveau_device *device)
case 0x96: case 0x96:
device->cname = "G96"; device->cname = "G96";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -225,8 +225,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -225,8 +225,8 @@ nv50_identify(struct nouveau_device *device)
case 0x98: case 0x98:
device->cname = "G98"; device->cname = "G98";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -253,8 +253,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -253,8 +253,8 @@ nv50_identify(struct nouveau_device *device)
case 0xa0: case 0xa0:
device->cname = "G200"; device->cname = "G200";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -281,8 +281,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -281,8 +281,8 @@ nv50_identify(struct nouveau_device *device)
case 0xaa: case 0xaa:
device->cname = "MCP77/MCP78"; device->cname = "MCP77/MCP78";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -309,8 +309,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -309,8 +309,8 @@ nv50_identify(struct nouveau_device *device)
case 0xac: case 0xac:
device->cname = "MCP79/MCP7A"; device->cname = "MCP79/MCP7A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -337,8 +337,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -337,8 +337,8 @@ nv50_identify(struct nouveau_device *device)
case 0xa3: case 0xa3:
device->cname = "GT215"; device->cname = "GT215";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -367,8 +367,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -367,8 +367,8 @@ nv50_identify(struct nouveau_device *device)
case 0xa5: case 0xa5:
device->cname = "GT216"; device->cname = "GT216";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -396,8 +396,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -396,8 +396,8 @@ nv50_identify(struct nouveau_device *device)
case 0xa8: case 0xa8:
device->cname = "GT218"; device->cname = "GT218";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -425,8 +425,8 @@ nv50_identify(struct nouveau_device *device) ...@@ -425,8 +425,8 @@ nv50_identify(struct nouveau_device *device)
case 0xaf: case 0xaf:
device->cname = "MCP89"; device->cname = "MCP89";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
...@@ -60,8 +60,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -60,8 +60,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xc0: case 0xc0:
device->cname = "GF100"; device->cname = "GF100";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -92,8 +92,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -92,8 +92,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xc4: case 0xc4:
device->cname = "GF104"; device->cname = "GF104";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -124,8 +124,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -124,8 +124,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xc3: case 0xc3:
device->cname = "GF106"; device->cname = "GF106";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -155,8 +155,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -155,8 +155,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xce: case 0xce:
device->cname = "GF114"; device->cname = "GF114";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -187,8 +187,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -187,8 +187,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xcf: case 0xcf:
device->cname = "GF116"; device->cname = "GF116";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -219,8 +219,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -219,8 +219,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xc1: case 0xc1:
device->cname = "GF108"; device->cname = "GF108";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -250,8 +250,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -250,8 +250,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xc8: case 0xc8:
device->cname = "GF110"; device->cname = "GF110";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -282,8 +282,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -282,8 +282,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xd9: case 0xd9:
device->cname = "GF119"; device->cname = "GF119";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -313,8 +313,8 @@ nvc0_identify(struct nouveau_device *device) ...@@ -313,8 +313,8 @@ nvc0_identify(struct nouveau_device *device)
case 0xd7: case 0xd7:
device->cname = "GF117"; device->cname = "GF117";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
...@@ -60,8 +60,8 @@ nve0_identify(struct nouveau_device *device) ...@@ -60,8 +60,8 @@ nve0_identify(struct nouveau_device *device)
case 0xe4: case 0xe4:
device->cname = "GK104"; device->cname = "GK104";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -93,8 +93,8 @@ nve0_identify(struct nouveau_device *device) ...@@ -93,8 +93,8 @@ nve0_identify(struct nouveau_device *device)
case 0xe7: case 0xe7:
device->cname = "GK107"; device->cname = "GK107";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -126,8 +126,8 @@ nve0_identify(struct nouveau_device *device) ...@@ -126,8 +126,8 @@ nve0_identify(struct nouveau_device *device)
case 0xe6: case 0xe6:
device->cname = "GK106"; device->cname = "GK106";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -176,8 +176,8 @@ nve0_identify(struct nouveau_device *device) ...@@ -176,8 +176,8 @@ nve0_identify(struct nouveau_device *device)
case 0xf0: case 0xf0:
device->cname = "GK110"; device->cname = "GK110";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -209,8 +209,8 @@ nve0_identify(struct nouveau_device *device) ...@@ -209,8 +209,8 @@ nve0_identify(struct nouveau_device *device)
case 0xf1: case 0xf1:
device->cname = "GK110B"; device->cname = "GK110B";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
...@@ -242,8 +242,8 @@ nve0_identify(struct nouveau_device *device) ...@@ -242,8 +242,8 @@ nve0_identify(struct nouveau_device *device)
case 0x108: case 0x108:
device->cname = "GK208"; device->cname = "GK208";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
...@@ -22,13 +22,87 @@ ...@@ -22,13 +22,87 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <engine/disp.h> #include "priv.h"
#include "outp.h"
#include "conn.h"
static int
nouveau_disp_hpd_check(struct nouveau_event *event, u32 types, int index)
{
struct nouveau_disp *disp = event->priv;
struct nvkm_output *outp;
list_for_each_entry(outp, &disp->outp, head) {
if (outp->conn->index == index) {
if (outp->conn->hpd.event)
return 0;
break;
}
}
return -ENOSYS;
}
int
_nouveau_disp_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_disp *disp = (void *)object;
struct nvkm_output *outp;
int ret;
list_for_each_entry(outp, &disp->outp, head) {
ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
if (ret && suspend)
goto fail_outp;
}
return nouveau_engine_fini(&disp->base, suspend);
fail_outp:
list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
nv_ofuncs(outp)->init(nv_object(outp));
}
return ret;
}
int
_nouveau_disp_init(struct nouveau_object *object)
{
struct nouveau_disp *disp = (void *)object;
struct nvkm_output *outp;
int ret;
ret = nouveau_engine_init(&disp->base);
if (ret)
return ret;
list_for_each_entry(outp, &disp->outp, head) {
ret = nv_ofuncs(outp)->init(nv_object(outp));
if (ret)
goto fail_outp;
}
return ret;
fail_outp:
list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
nv_ofuncs(outp)->fini(nv_object(outp), false);
}
return ret;
}
void void
_nouveau_disp_dtor(struct nouveau_object *object) _nouveau_disp_dtor(struct nouveau_object *object)
{ {
struct nouveau_disp *disp = (void *)object; struct nouveau_disp *disp = (void *)object;
struct nvkm_output *outp, *outt;
nouveau_event_destroy(&disp->vblank); nouveau_event_destroy(&disp->vblank);
list_for_each_entry_safe(outp, outt, &disp->outp, head) {
nouveau_object_ref(NULL, (struct nouveau_object **)&outp);
}
nouveau_engine_destroy(&disp->base); nouveau_engine_destroy(&disp->base);
} }
...@@ -39,8 +113,15 @@ nouveau_disp_create_(struct nouveau_object *parent, ...@@ -39,8 +113,15 @@ nouveau_disp_create_(struct nouveau_object *parent,
const char *intname, const char *extname, const char *intname, const char *extname,
int length, void **pobject) int length, void **pobject)
{ {
struct nouveau_disp_impl *impl = (void *)oclass;
struct nouveau_bios *bios = nouveau_bios(parent);
struct nouveau_disp *disp; struct nouveau_disp *disp;
int ret; struct nouveau_oclass **sclass;
struct nouveau_object *object;
struct dcb_output dcbE;
u8 hpd = 0, ver, hdr;
u32 data;
int ret, i;
ret = nouveau_engine_create_(parent, engine, oclass, true, ret = nouveau_engine_create_(parent, engine, oclass, true,
intname, extname, length, pobject); intname, extname, length, pobject);
...@@ -48,5 +129,42 @@ nouveau_disp_create_(struct nouveau_object *parent, ...@@ -48,5 +129,42 @@ nouveau_disp_create_(struct nouveau_object *parent,
if (ret) if (ret)
return ret; return ret;
return nouveau_event_create(heads, &disp->vblank); INIT_LIST_HEAD(&disp->outp);
/* create output objects for each display path in the vbios */
i = -1;
while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
if (dcbE.type == DCB_OUTPUT_UNUSED)
continue;
if (dcbE.type == DCB_OUTPUT_EOL)
break;
data = dcbE.location << 4 | dcbE.type;
oclass = nvkm_output_oclass;
sclass = impl->outp;
while (sclass && sclass[0]) {
if (sclass[0]->handle == data) {
oclass = sclass[0];
break;
}
sclass++;
}
nouveau_object_ctor(*pobject, *pobject, oclass,
&dcbE, i, &object);
hpd = max(hpd, (u8)(dcbE.connector + 1));
}
ret = nouveau_event_create(3, hpd, &disp->hpd);
if (ret)
return ret;
disp->hpd->priv = disp;
disp->hpd->check = nouveau_disp_hpd_check;
ret = nouveau_event_create(1, heads, &disp->vblank);
if (ret)
return ret;
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
*/
#include <subdev/gpio.h>
#include "conn.h"
#include "outp.h"
static void
nvkm_connector_hpd_work(struct work_struct *w)
{
struct nvkm_connector *conn = container_of(w, typeof(*conn), hpd.work);
struct nouveau_disp *disp = nouveau_disp(conn);
struct nouveau_gpio *gpio = nouveau_gpio(conn);
u32 send = NVKM_HPD_UNPLUG;
if (gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.event->index))
send = NVKM_HPD_PLUG;
nouveau_event_trigger(disp->hpd, send, conn->index);
nouveau_event_get(conn->hpd.event);
}
static int
nvkm_connector_hpd(void *data, u32 type, int index)
{
struct nvkm_connector *conn = data;
DBG("HPD: %d\n", type);
schedule_work(&conn->hpd.work);
return NVKM_EVENT_DROP;
}
int
_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
{
struct nvkm_connector *conn = (void *)object;
if (conn->hpd.event)
nouveau_event_put(conn->hpd.event);
return nouveau_object_fini(&conn->base, suspend);
}
int
_nvkm_connector_init(struct nouveau_object *object)
{
struct nvkm_connector *conn = (void *)object;
int ret = nouveau_object_init(&conn->base);
if (ret == 0) {
if (conn->hpd.event)
nouveau_event_get(conn->hpd.event);
}
return ret;
}
void
_nvkm_connector_dtor(struct nouveau_object *object)
{
struct nvkm_connector *conn = (void *)object;
nouveau_event_ref(NULL, &conn->hpd.event);
nouveau_object_destroy(&conn->base);
}
int
nvkm_connector_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
struct nvbios_connE *info, int index,
int length, void **pobject)
{
static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
struct nouveau_gpio *gpio = nouveau_gpio(parent);
struct nouveau_disp *disp = (void *)engine;
struct nvkm_connector *conn;
struct nvkm_output *outp;
struct dcb_gpio_func func;
int ret;
list_for_each_entry(outp, &disp->outp, head) {
if (outp->conn && outp->conn->index == index) {
atomic_inc(&nv_object(outp->conn)->refcount);
*pobject = outp->conn;
return 1;
}
}
ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
conn = *pobject;
if (ret)
return ret;
conn->info = *info;
conn->index = index;
DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
info->type, info->location, info->hpd, info->dp,
info->di, info->sr, info->lcdid);
if ((info->hpd = ffs(info->hpd))) {
if (--info->hpd >= ARRAY_SIZE(hpd)) {
ERR("hpd %02x unknown\n", info->hpd);
goto done;
}
info->hpd = hpd[info->hpd];
ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
if (ret) {
ERR("func %02x lookup failed, %d\n", info->hpd, ret);
goto done;
}
ret = nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED,
func.line, nvkm_connector_hpd,
conn, &conn->hpd.event);
if (ret) {
ERR("func %02x failed, %d\n", info->hpd, ret);
} else {
DBG("func %02x (HPD)\n", info->hpd);
}
}
done:
INIT_WORK(&conn->hpd.work, nvkm_connector_hpd_work);
return 0;
}
int
_nvkm_connector_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *info, u32 index,
struct nouveau_object **pobject)
{
struct nvkm_connector *conn;
int ret;
ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
*pobject = nv_object(conn);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass *
nvkm_connector_oclass = &(struct nvkm_connector_impl) {
.base = {
.handle = 0,
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nvkm_connector_ctor,
.dtor = _nvkm_connector_dtor,
.init = _nvkm_connector_init,
.fini = _nvkm_connector_fini,
},
},
}.base;
#ifndef __NVKM_DISP_CONN_H__
#define __NVKM_DISP_CONN_H__
#include "priv.h"
struct nvkm_connector {
struct nouveau_object base;
struct list_head head;
struct nvbios_connE info;
int index;
struct {
struct nouveau_eventh *event;
struct work_struct work;
} hpd;
};
#define nvkm_connector_create(p,e,c,b,i,d) \
nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
#define nvkm_connector_destroy(d) ({ \
struct nvkm_connector *disp = (d); \
_nvkm_connector_dtor(nv_object(disp)); \
})
#define nvkm_connector_init(d) ({ \
struct nvkm_connector *disp = (d); \
_nvkm_connector_init(nv_object(disp)); \
})
#define nvkm_connector_fini(d,s) ({ \
struct nvkm_connector *disp = (d); \
_nvkm_connector_fini(nv_object(disp), (s)); \
})
int nvkm_connector_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, struct nvbios_connE *,
int, int, void **);
int _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void _nvkm_connector_dtor(struct nouveau_object *);
int _nvkm_connector_init(struct nouveau_object *);
int _nvkm_connector_fini(struct nouveau_object *, bool);
struct nvkm_connector_impl {
struct nouveau_oclass base;
};
#ifndef MSG
#define MSG(l,f,a...) do { \
struct nvkm_connector *_conn = (void *)conn; \
nv_##l(nv_object(conn)->engine, "%02x:%02x%02x: "f, _conn->index, \
_conn->info.location, _conn->info.type, ##a); \
} while(0)
#define DBG(f,a...) MSG(debug, f, ##a)
#define ERR(f,a...) MSG(error, f, ##a)
#endif
#endif
...@@ -30,42 +30,38 @@ ...@@ -30,42 +30,38 @@
#include <engine/disp.h> #include <engine/disp.h>
#include "dport.h" #include <core/class.h>
#define DBG(fmt, args...) nv_debug(dp->disp, "DP:%04x:%04x: " fmt, \ #include "dport.h"
dp->outp->hasht, dp->outp->hashm, ##args) #include "outpdp.h"
#define ERR(fmt, args...) nv_error(dp->disp, "DP:%04x:%04x: " fmt, \
dp->outp->hasht, dp->outp->hashm, ##args)
/****************************************************************************** /******************************************************************************
* link training * link training
*****************************************************************************/ *****************************************************************************/
struct dp_state { struct dp_state {
const struct nouveau_dp_func *func; struct nvkm_output_dp *outp;
struct nouveau_disp *disp;
struct dcb_output *outp;
struct nvbios_dpout info;
u8 version;
struct nouveau_i2c_port *aux;
int head;
u8 dpcd[16];
int link_nr; int link_nr;
u32 link_bw; u32 link_bw;
u8 stat[6]; u8 stat[6];
u8 conf[4]; u8 conf[4];
bool pc2;
u8 pc2stat;
u8 pc2conf[2];
}; };
static int static int
dp_set_link_config(struct dp_state *dp) dp_set_link_config(struct dp_state *dp)
{ {
struct nouveau_disp *disp = dp->disp; struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
struct nvkm_output_dp *outp = dp->outp;
struct nouveau_disp *disp = nouveau_disp(outp);
struct nouveau_bios *bios = nouveau_bios(disp); struct nouveau_bios *bios = nouveau_bios(disp);
struct nvbios_init init = { struct nvbios_init init = {
.subdev = nv_subdev(dp->disp), .subdev = nv_subdev(disp),
.bios = bios, .bios = bios,
.offset = 0x0000, .offset = 0x0000,
.outp = dp->outp, .outp = &outp->base.info,
.crtc = dp->head, .crtc = -1,
.execute = 1, .execute = 1,
}; };
u32 lnkcmp; u32 lnkcmp;
...@@ -75,8 +71,8 @@ dp_set_link_config(struct dp_state *dp) ...@@ -75,8 +71,8 @@ dp_set_link_config(struct dp_state *dp)
DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
/* set desired link configuration on the source */ /* set desired link configuration on the source */
if ((lnkcmp = dp->info.lnkcmp)) { if ((lnkcmp = dp->outp->info.lnkcmp)) {
if (dp->version < 0x30) { if (outp->version < 0x30) {
while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
lnkcmp += 4; lnkcmp += 4;
init.offset = nv_ro16(bios, lnkcmp + 2); init.offset = nv_ro16(bios, lnkcmp + 2);
...@@ -89,76 +85,112 @@ dp_set_link_config(struct dp_state *dp) ...@@ -89,76 +85,112 @@ dp_set_link_config(struct dp_state *dp)
nvbios_exec(&init); nvbios_exec(&init);
} }
ret = dp->func->lnk_ctl(dp->disp, dp->outp, dp->head, ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
dp->link_nr, dp->link_bw / 27000, outp->dpcd[DPCD_RC02] &
dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP);
DPCD_RC02_ENHANCED_FRAME_CAP);
if (ret) { if (ret) {
ERR("lnk_ctl failed with %d\n", ret); if (ret < 0)
ERR("lnk_ctl failed with %d\n", ret);
return ret; return ret;
} }
impl->lnk_pwr(outp, dp->link_nr);
/* set desired link configuration on the sink */ /* set desired link configuration on the sink */
sink[0] = dp->link_bw / 27000; sink[0] = dp->link_bw / 27000;
sink[1] = dp->link_nr; sink[1] = dp->link_nr;
if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
return nv_wraux(dp->aux, DPCD_LC00, sink, 2); return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
} }
static void static void
dp_set_training_pattern(struct dp_state *dp, u8 pattern) dp_set_training_pattern(struct dp_state *dp, u8 pattern)
{ {
struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
struct nvkm_output_dp *outp = dp->outp;
u8 sink_tp; u8 sink_tp;
DBG("training pattern %d\n", pattern); DBG("training pattern %d\n", pattern);
dp->func->pattern(dp->disp, dp->outp, dp->head, pattern); impl->pattern(outp, pattern);
nv_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
sink_tp |= pattern; sink_tp |= pattern;
nv_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
} }
static int static int
dp_link_train_commit(struct dp_state *dp) dp_link_train_commit(struct dp_state *dp, bool pc)
{ {
int i; struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
struct nvkm_output_dp *outp = dp->outp;
int ret, i;
for (i = 0; i < dp->link_nr; i++) { for (i = 0; i < dp->link_nr; i++) {
u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
u8 lpre = (lane & 0x0c) >> 2; u8 lpre = (lane & 0x0c) >> 2;
u8 lvsw = (lane & 0x03) >> 0; u8 lvsw = (lane & 0x03) >> 0;
u8 hivs = 3 - lpre;
u8 hipe = 3;
u8 hipc = 3;
if (lpc2 >= hipc)
lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
if (lpre >= hipe) {
lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
lvsw = hivs = 3 - (lpre & 3);
} else
if (lvsw >= hivs) {
lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
}
dp->conf[i] = (lpre << 3) | lvsw; dp->conf[i] = (lpre << 3) | lvsw;
if (lvsw == 3) dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
dp->conf[i] |= DPCD_LC03_MAX_SWING_REACHED;
if (lpre == 3)
dp->conf[i] |= DPCD_LC03_MAX_PRE_EMPHASIS_REACHED;
DBG("config lane %d %02x\n", i, dp->conf[i]); DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2);
dp->func->drv_ctl(dp->disp, dp->outp, dp->head, i, lvsw, lpre); impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
} }
return nv_wraux(dp->aux, DPCD_LC03(0), dp->conf, 4); ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4);
if (ret)
return ret;
if (pc) {
ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2);
if (ret)
return ret;
}
return 0;
} }
static int static int
dp_link_train_update(struct dp_state *dp, u32 delay) dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
{ {
struct nvkm_output_dp *outp = dp->outp;
int ret; int ret;
if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
else else
udelay(delay); udelay(delay);
ret = nv_rdaux(dp->aux, DPCD_LS02, dp->stat, 6); ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6);
if (ret) if (ret)
return ret; return ret;
DBG("status %6ph\n", dp->stat); if (pc) {
ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1);
if (ret)
dp->pc2stat = 0x00;
DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
} else {
DBG("status %6ph\n", dp->stat);
}
return 0; return 0;
} }
...@@ -172,8 +204,8 @@ dp_link_train_cr(struct dp_state *dp) ...@@ -172,8 +204,8 @@ dp_link_train_cr(struct dp_state *dp)
dp_set_training_pattern(dp, 1); dp_set_training_pattern(dp, 1);
do { do {
if (dp_link_train_commit(dp) || if (dp_link_train_commit(dp, false) ||
dp_link_train_update(dp, 100)) dp_link_train_update(dp, false, 100))
break; break;
cr_done = true; cr_done = true;
...@@ -199,16 +231,17 @@ dp_link_train_cr(struct dp_state *dp) ...@@ -199,16 +231,17 @@ dp_link_train_cr(struct dp_state *dp)
static int static int
dp_link_train_eq(struct dp_state *dp) dp_link_train_eq(struct dp_state *dp)
{ {
struct nvkm_output_dp *outp = dp->outp;
bool eq_done = false, cr_done = true; bool eq_done = false, cr_done = true;
int tries = 0, i; int tries = 0, i;
if (dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
dp_set_training_pattern(dp, 3); dp_set_training_pattern(dp, 3);
else else
dp_set_training_pattern(dp, 2); dp_set_training_pattern(dp, 2);
do { do {
if (dp_link_train_update(dp, 400)) if (dp_link_train_update(dp, dp->pc2, 400))
break; break;
eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
...@@ -221,7 +254,7 @@ dp_link_train_eq(struct dp_state *dp) ...@@ -221,7 +254,7 @@ dp_link_train_eq(struct dp_state *dp)
eq_done = false; eq_done = false;
} }
if (dp_link_train_commit(dp)) if (dp_link_train_commit(dp, dp->pc2))
break; break;
} while (!eq_done && cr_done && ++tries <= 5); } while (!eq_done && cr_done && ++tries <= 5);
...@@ -231,123 +264,109 @@ dp_link_train_eq(struct dp_state *dp) ...@@ -231,123 +264,109 @@ dp_link_train_eq(struct dp_state *dp)
static void static void
dp_link_train_init(struct dp_state *dp, bool spread) dp_link_train_init(struct dp_state *dp, bool spread)
{ {
struct nvkm_output_dp *outp = dp->outp;
struct nouveau_disp *disp = nouveau_disp(outp);
struct nouveau_bios *bios = nouveau_bios(disp);
struct nvbios_init init = { struct nvbios_init init = {
.subdev = nv_subdev(dp->disp), .subdev = nv_subdev(disp),
.bios = nouveau_bios(dp->disp), .bios = bios,
.outp = dp->outp, .outp = &outp->base.info,
.crtc = dp->head, .crtc = -1,
.execute = 1, .execute = 1,
}; };
/* set desired spread */ /* set desired spread */
if (spread) if (spread)
init.offset = dp->info.script[2]; init.offset = outp->info.script[2];
else else
init.offset = dp->info.script[3]; init.offset = outp->info.script[3];
nvbios_exec(&init); nvbios_exec(&init);
/* pre-train script */ /* pre-train script */
init.offset = dp->info.script[0]; init.offset = outp->info.script[0];
nvbios_exec(&init); nvbios_exec(&init);
} }
static void static void
dp_link_train_fini(struct dp_state *dp) dp_link_train_fini(struct dp_state *dp)
{ {
struct nvkm_output_dp *outp = dp->outp;
struct nouveau_disp *disp = nouveau_disp(outp);
struct nouveau_bios *bios = nouveau_bios(disp);
struct nvbios_init init = { struct nvbios_init init = {
.subdev = nv_subdev(dp->disp), .subdev = nv_subdev(disp),
.bios = nouveau_bios(dp->disp), .bios = bios,
.outp = dp->outp, .outp = &outp->base.info,
.crtc = dp->head, .crtc = -1,
.execute = 1, .execute = 1,
}; };
/* post-train script */ /* post-train script */
init.offset = dp->info.script[1], init.offset = outp->info.script[1],
nvbios_exec(&init); nvbios_exec(&init);
} }
int static const struct dp_rates {
nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, u32 rate;
struct dcb_output *outp, int head, u32 datarate) u8 bw;
u8 nr;
} nouveau_dp_rates[] = {
{ 2160000, 0x14, 4 },
{ 1080000, 0x0a, 4 },
{ 1080000, 0x14, 2 },
{ 648000, 0x06, 4 },
{ 540000, 0x0a, 2 },
{ 540000, 0x14, 1 },
{ 324000, 0x06, 2 },
{ 270000, 0x0a, 1 },
{ 162000, 0x06, 1 },
{}
};
void
nouveau_dp_train(struct work_struct *w)
{ {
struct nouveau_bios *bios = nouveau_bios(disp); struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
struct nouveau_i2c *i2c = nouveau_i2c(disp); struct nouveau_disp *disp = nouveau_disp(outp);
const struct dp_rates *cfg = nouveau_dp_rates;
struct dp_state _dp = { struct dp_state _dp = {
.disp = disp,
.func = func,
.outp = outp, .outp = outp,
.head = head,
}, *dp = &_dp; }, *dp = &_dp;
const u32 bw_list[] = { 540000, 270000, 162000, 0 }; u32 datarate = 0;
const u32 *link_bw = bw_list;
u8 hdr, cnt, len;
u32 data;
int ret; int ret;
/* find the bios displayport data relevant to this output */
data = nvbios_dpout_match(bios, outp->hasht, outp->hashm, &dp->version,
&hdr, &cnt, &len, &dp->info);
if (!data) {
ERR("bios data not found\n");
return -EINVAL;
}
/* acquire the aux channel and fetch some info about the display */
if (outp->location)
dp->aux = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev));
else
dp->aux = i2c->find(i2c, NV_I2C_TYPE_DCBI2C(outp->i2c_index));
if (!dp->aux) {
ERR("no aux channel?!\n");
return -ENODEV;
}
ret = nv_rdaux(dp->aux, 0x00000, dp->dpcd, sizeof(dp->dpcd));
if (ret) {
/* it's possible the display has been unplugged before we
* get here. we still need to execute the full set of
* vbios scripts, and program the OR at a high enough
* frequency to satisfy the target mode. failure to do
* so results at best in an UPDATE hanging, and at worst
* with PDISP running away to join the circus.
*/
dp->dpcd[1] = link_bw[0] / 27000;
dp->dpcd[2] = 4;
dp->dpcd[3] = 0x00;
ERR("failed to read DPCD\n");
}
/* bring capabilities within encoder limits */ /* bring capabilities within encoder limits */
if (nv_oclass(disp)->handle < NV_ENGINE(DISP, 0x90)) if (nv_mclass(disp) < NVD0_DISP_CLASS)
dp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
if ((dp->dpcd[2] & 0x1f) > dp->outp->dpconf.link_nr) { if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
dp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
dp->dpcd[2] |= dp->outp->dpconf.link_nr; outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
}
if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
outp->dpcd[1] = outp->base.info.dpconf.link_bw;
dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
/* restrict link config to the lowest required rate, if requested */
if (datarate) {
datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
while (cfg[1].rate >= datarate)
cfg++;
} }
if (dp->dpcd[1] > dp->outp->dpconf.link_bw) cfg--;
dp->dpcd[1] = dp->outp->dpconf.link_bw;
/* adjust required bandwidth for 8B/10B coding overhead */ /* disable link interrupt handling during link training */
datarate = (datarate / 8) * 10; nouveau_event_put(outp->irq);
/* enable down-spreading and execute pre-train script from vbios */ /* enable down-spreading and execute pre-train script from vbios */
dp_link_train_init(dp, dp->dpcd[3] & 0x01); dp_link_train_init(dp, outp->dpcd[3] & 0x01);
/* start off at highest link rate supported by encoder and display */ while (ret = -EIO, (++cfg)->rate) {
while (*link_bw > (dp->dpcd[1] * 27000)) /* select next configuration supported by encoder and sink */
link_bw++; while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
while ((ret = -EIO) && link_bw[0]) { cfg++;
/* find minimum required lane count at this link rate */ dp->link_bw = cfg->bw * 27000;
dp->link_nr = dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT; dp->link_nr = cfg->nr;
while ((dp->link_nr >> 1) * link_bw[0] > datarate)
dp->link_nr >>= 1;
/* drop link rate to minimum with this lane count */
while ((link_bw[1] * dp->link_nr) > datarate)
link_bw++;
dp->link_bw = link_bw[0];
/* program selected link configuration */ /* program selected link configuration */
ret = dp_set_link_config(dp); ret = dp_set_link_config(dp);
...@@ -364,17 +383,18 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, ...@@ -364,17 +383,18 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
*/ */
break; break;
} }
/* retry at lower rate */
link_bw++;
} }
/* finish link training */ /* finish link training and execute post-train script from vbios */
dp_set_training_pattern(dp, 0); dp_set_training_pattern(dp, 0);
if (ret < 0) if (ret < 0)
ERR("link training failed\n"); ERR("link training failed\n");
/* execute post-train script from vbios */
dp_link_train_fini(dp); dp_link_train_fini(dp);
return (ret < 0) ? false : true;
/* signal completion and enable link interrupt handling */
DBG("training complete\n");
atomic_set(&outp->lt.done, 1);
wake_up(&outp->lt.wait);
nouveau_event_get(outp->irq);
} }
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e #define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e
/* DPCD Link Configuration */ /* DPCD Link Configuration */
#define DPCD_LC00 0x00100 #define DPCD_LC00_LINK_BW_SET 0x00100
#define DPCD_LC00_LINK_BW_SET 0xff
#define DPCD_LC01 0x00101 #define DPCD_LC01 0x00101
#define DPCD_LC01_ENHANCED_FRAME_EN 0x80 #define DPCD_LC01_ENHANCED_FRAME_EN 0x80
#define DPCD_LC01_LANE_COUNT_SET 0x1f #define DPCD_LC01_LANE_COUNT_SET 0x1f
...@@ -25,6 +24,16 @@ ...@@ -25,6 +24,16 @@
#define DPCD_LC03_PRE_EMPHASIS_SET 0x18 #define DPCD_LC03_PRE_EMPHASIS_SET 0x18
#define DPCD_LC03_MAX_SWING_REACHED 0x04 #define DPCD_LC03_MAX_SWING_REACHED 0x04
#define DPCD_LC03_VOLTAGE_SWING_SET 0x03 #define DPCD_LC03_VOLTAGE_SWING_SET 0x03
#define DPCD_LC0F 0x0010f
#define DPCD_LC0F_LANE1_MAX_POST_CURSOR2_REACHED 0x40
#define DPCD_LC0F_LANE1_POST_CURSOR2_SET 0x30
#define DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED 0x04
#define DPCD_LC0F_LANE0_POST_CURSOR2_SET 0x03
#define DPCD_LC10 0x00110
#define DPCD_LC10_LANE3_MAX_POST_CURSOR2_REACHED 0x40
#define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30
#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04
#define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03
/* DPCD Link/Sink Status */ /* DPCD Link/Sink Status */
#define DPCD_LS02 0x00202 #define DPCD_LS02 0x00202
...@@ -55,24 +64,12 @@ ...@@ -55,24 +64,12 @@
#define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30 #define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30
#define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c #define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c
#define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03 #define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03
#define DPCD_LS0C 0x0020c
#define DPCD_LS0C_LANE3_POST_CURSOR2 0xc0
#define DPCD_LS0C_LANE2_POST_CURSOR2 0x30
#define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c
#define DPCD_LS0C_LANE0_POST_CURSOR2 0x03
struct nouveau_disp; void nouveau_dp_train(struct work_struct *);
struct dcb_output;
struct nouveau_dp_func {
int (*pattern)(struct nouveau_disp *, struct dcb_output *,
int head, int pattern);
int (*lnk_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
int link_nr, int link_bw, bool enh_frame);
int (*drv_ctl)(struct nouveau_disp *, struct dcb_output *, int head,
int lane, int swing, int preem);
};
extern const struct nouveau_dp_func nv94_sor_dp_func;
extern const struct nouveau_dp_func nvd0_sor_dp_func;
extern const struct nouveau_dp_func nv50_pior_dp_func;
int nouveau_dp_train(struct nouveau_disp *, const struct nouveau_dp_func *,
struct dcb_output *, int, u32);
#endif #endif
...@@ -81,7 +81,6 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -81,7 +81,6 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
...@@ -94,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { ...@@ -94,6 +93,7 @@ gm107_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
......
...@@ -86,13 +86,13 @@ nv04_disp_sclass[] = { ...@@ -86,13 +86,13 @@ nv04_disp_sclass[] = {
******************************************************************************/ ******************************************************************************/
static void static void
nv04_disp_vblank_enable(struct nouveau_event *event, int head) nv04_disp_vblank_enable(struct nouveau_event *event, int type, int head)
{ {
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001); nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000001);
} }
static void static void
nv04_disp_vblank_disable(struct nouveau_event *event, int head) nv04_disp_vblank_disable(struct nouveau_event *event, int type, int head)
{ {
nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000); nv_wr32(event->priv, 0x600140 + (head * 0x2000) , 0x00000000);
} }
...@@ -106,12 +106,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev) ...@@ -106,12 +106,12 @@ nv04_disp_intr(struct nouveau_subdev *subdev)
u32 pvideo; u32 pvideo;
if (crtc0 & 0x00000001) { if (crtc0 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 0); nouveau_event_trigger(priv->base.vblank, 1, 0);
nv_wr32(priv, 0x600100, 0x00000001); nv_wr32(priv, 0x600100, 0x00000001);
} }
if (crtc1 & 0x00000001) { if (crtc1 & 0x00000001) {
nouveau_event_trigger(priv->base.vblank, 1); nouveau_event_trigger(priv->base.vblank, 1, 1);
nv_wr32(priv, 0x602100, 0x00000001); nv_wr32(priv, 0x602100, 0x00000001);
} }
......
...@@ -829,13 +829,13 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, ...@@ -829,13 +829,13 @@ nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
} }
static void static void
nv50_disp_base_vblank_enable(struct nouveau_event *event, int head) nv50_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
{ {
nv_mask(event->priv, 0x61002c, (4 << head), (4 << head)); nv_mask(event->priv, 0x61002c, (4 << head), (4 << head));
} }
static void static void
nv50_disp_base_vblank_disable(struct nouveau_event *event, int head) nv50_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
{ {
nv_mask(event->priv, 0x61002c, (4 << head), 0); nv_mask(event->priv, 0x61002c, (4 << head), 0);
} }
...@@ -1114,19 +1114,20 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) ...@@ -1114,19 +1114,20 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
} }
static u16 static struct nvkm_output *
exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_outp *info) struct nvbios_outp *info)
{ {
struct nouveau_bios *bios = nouveau_bios(priv); struct nouveau_bios *bios = nouveau_bios(priv);
u16 mask, type, data; struct nvkm_output *outp;
u16 mask, type;
if (outp < 4) { if (or < 4) {
type = DCB_OUTPUT_ANALOG; type = DCB_OUTPUT_ANALOG;
mask = 0; mask = 0;
} else } else
if (outp < 8) { if (or < 8) {
switch (ctrl & 0x00000f00) { switch (ctrl & 0x00000f00) {
case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
...@@ -1136,45 +1137,48 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, ...@@ -1136,45 +1137,48 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
default: default:
nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
return 0x0000; return NULL;
} }
outp -= 4; or -= 4;
} else { } else {
outp = outp - 8; or = or - 8;
type = 0x0010; type = 0x0010;
mask = 0; mask = 0;
switch (ctrl & 0x00000f00) { switch (ctrl & 0x00000f00) {
case 0x00000000: type |= priv->pior.type[outp]; break; case 0x00000000: type |= priv->pior.type[or]; break;
default: default:
nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl); nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
return 0x0000; return NULL;
} }
} }
mask = 0x00c0 & (mask << 6); mask = 0x00c0 & (mask << 6);
mask |= 0x0001 << outp; mask |= 0x0001 << or;
mask |= 0x0100 << head; mask |= 0x0100 << head;
data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); list_for_each_entry(outp, &priv->base.outp, head) {
if (!data) if ((outp->info.hasht & 0xff) == type &&
return 0x0000; (outp->info.hashm & mask) == mask) {
*data = nvbios_outp_match(bios, outp->info.hasht,
/* off-chip encoders require matching the exact encoder type */ outp->info.hashm,
if (dcb->location != 0) ver, hdr, cnt, len, info);
type |= dcb->extdev << 8; if (!*data)
return NULL;
return outp;
}
}
return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); return NULL;
} }
static bool static struct nvkm_output *
exec_script(struct nv50_disp_priv *priv, int head, int id) exec_script(struct nv50_disp_priv *priv, int head, int id)
{ {
struct nouveau_bios *bios = nouveau_bios(priv); struct nouveau_bios *bios = nouveau_bios(priv);
struct nvkm_output *outp;
struct nvbios_outp info; struct nvbios_outp info;
struct dcb_output dcb;
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
u16 data; u32 data, ctrl = 0;
u32 ctrl = 0x00000000;
u32 reg; u32 reg;
int i; int i;
...@@ -1204,36 +1208,35 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) ...@@ -1204,36 +1208,35 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
} }
if (!(ctrl & (1 << head))) if (!(ctrl & (1 << head)))
return false; return NULL;
i--; i--;
data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
if (data) { if (outp) {
struct nvbios_init init = { struct nvbios_init init = {
.subdev = nv_subdev(priv), .subdev = nv_subdev(priv),
.bios = bios, .bios = bios,
.offset = info.script[id], .offset = info.script[id],
.outp = &dcb, .outp = &outp->info,
.crtc = head, .crtc = head,
.execute = 1, .execute = 1,
}; };
return nvbios_exec(&init) == 0; nvbios_exec(&init);
} }
return false; return outp;
} }
static u32 static struct nvkm_output *
exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
struct dcb_output *outp)
{ {
struct nouveau_bios *bios = nouveau_bios(priv); struct nouveau_bios *bios = nouveau_bios(priv);
struct nvkm_output *outp;
struct nvbios_outp info1; struct nvbios_outp info1;
struct nvbios_ocfg info2; struct nvbios_ocfg info2;
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
u32 ctrl = 0x00000000; u32 data, ctrl = 0;
u32 data, conf = ~0;
u32 reg; u32 reg;
int i; int i;
...@@ -1263,37 +1266,37 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, ...@@ -1263,37 +1266,37 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
} }
if (!(ctrl & (1 << head))) if (!(ctrl & (1 << head)))
return conf; return NULL;
i--; i--;
data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1); outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
if (!data) if (!data)
return conf; return NULL;
if (outp->location == 0) { if (outp->info.location == 0) {
switch (outp->type) { switch (outp->info.type) {
case DCB_OUTPUT_TMDS: case DCB_OUTPUT_TMDS:
conf = (ctrl & 0x00000f00) >> 8; *conf = (ctrl & 0x00000f00) >> 8;
if (pclk >= 165000) if (pclk >= 165000)
conf |= 0x0100; *conf |= 0x0100;
break; break;
case DCB_OUTPUT_LVDS: case DCB_OUTPUT_LVDS:
conf = priv->sor.lvdsconf; *conf = priv->sor.lvdsconf;
break; break;
case DCB_OUTPUT_DP: case DCB_OUTPUT_DP:
conf = (ctrl & 0x00000f00) >> 8; *conf = (ctrl & 0x00000f00) >> 8;
break; break;
case DCB_OUTPUT_ANALOG: case DCB_OUTPUT_ANALOG:
default: default:
conf = 0x00ff; *conf = 0x00ff;
break; break;
} }
} else { } else {
conf = (ctrl & 0x00000f00) >> 8; *conf = (ctrl & 0x00000f00) >> 8;
pclk = pclk / 2; pclk = pclk / 2;
} }
data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
if (data && id < 0xff) { if (data && id < 0xff) {
data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
if (data) { if (data) {
...@@ -1301,7 +1304,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, ...@@ -1301,7 +1304,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
.subdev = nv_subdev(priv), .subdev = nv_subdev(priv),
.bios = bios, .bios = bios,
.offset = data, .offset = data,
.outp = outp, .outp = &outp->info,
.crtc = head, .crtc = head,
.execute = 1, .execute = 1,
}; };
...@@ -1310,7 +1313,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, ...@@ -1310,7 +1313,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
} }
} }
return conf; return outp;
} }
static void static void
...@@ -1322,7 +1325,35 @@ nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head) ...@@ -1322,7 +1325,35 @@ nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
static void static void
nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
{ {
exec_script(priv, head, 2); struct nvkm_output *outp = exec_script(priv, head, 2);
/* the binary driver does this outside of the supervisor handling
* (after the third supervisor from a detach). we (currently?)
* allow both detach/attach to happen in the same set of
* supervisor interrupts, so it would make sense to execute this
* (full power down?) script after all the detach phases of the
* supervisor handling. like with training if needed from the
* second supervisor, nvidia doesn't do this, so who knows if it's
* entirely safe, but it does appear to work..
*
* without this script being run, on some configurations i've
* seen, switching from DP to TMDS on a DP connector may result
* in a blank screen (SOR_PWR off/on can restore it)
*/
if (outp && outp->info.type == DCB_OUTPUT_DP) {
struct nvkm_output_dp *outpdp = (void *)outp;
struct nvbios_init init = {
.subdev = nv_subdev(priv),
.bios = nouveau_bios(priv),
.outp = &outp->info,
.crtc = head,
.offset = outpdp->info.script[4],
.execute = 1,
};
nvbios_exec(&init);
atomic_set(&outpdp->lt.done, 0);
}
} }
static void static void
...@@ -1444,56 +1475,83 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, ...@@ -1444,56 +1475,83 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
static void static void
nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
{ {
struct dcb_output outp; struct nvkm_output *outp;
u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
u32 hval, hreg = 0x614200 + (head * 0x800); u32 hval, hreg = 0x614200 + (head * 0x800);
u32 oval, oreg; u32 oval, oreg;
u32 mask; u32 mask, conf;
u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
if (conf != ~0) {
if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
u32 soff = (ffs(outp.or) - 1) * 0x08;
u32 ctrl = nv_rd32(priv, 0x610794 + soff);
u32 datarate;
switch ((ctrl & 0x000f0000) >> 16) {
case 6: datarate = pclk * 30 / 8; break;
case 5: datarate = pclk * 24 / 8; break;
case 2:
default:
datarate = pclk * 18 / 8;
break;
}
nouveau_dp_train(&priv->base, priv->sor.dp, outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
&outp, head, datarate); if (!outp)
} return;
/* we allow both encoder attach and detach operations to occur
* within a single supervisor (ie. modeset) sequence. the
* encoder detach scripts quite often switch off power to the
* lanes, which requires the link to be re-trained.
*
* this is not generally an issue as the sink "must" (heh)
* signal an irq when it's lost sync so the driver can
* re-train.
*
* however, on some boards, if one does not configure at least
* the gpu side of the link *before* attaching, then various
* things can go horribly wrong (PDISP disappearing from mmio,
* third supervisor never happens, etc).
*
* the solution is simply to retrain here, if necessary. last
* i checked, the binary driver userspace does not appear to
* trigger this situation (it forces an UPDATE between steps).
*/
if (outp->info.type == DCB_OUTPUT_DP) {
u32 soff = (ffs(outp->info.or) - 1) * 0x08;
u32 ctrl, datarate;
exec_clkcmp(priv, head, 0, pclk, &outp); if (outp->info.location == 0) {
ctrl = nv_rd32(priv, 0x610794 + soff);
if (!outp.location && outp.type == DCB_OUTPUT_ANALOG) { soff = 1;
oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
oval = 0x00000000;
hval = 0x00000000;
mask = 0xffffffff;
} else
if (!outp.location) {
if (outp.type == DCB_OUTPUT_DP)
nv50_disp_intr_unk20_2_dp(priv, &outp, pclk);
oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
hval = 0x00000000;
mask = 0x00000707;
} else { } else {
oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800; ctrl = nv_rd32(priv, 0x610b80 + soff);
oval = 0x00000001; soff = 2;
hval = 0x00000001;
mask = 0x00000707;
} }
nv_mask(priv, hreg, 0x0000000f, hval); switch ((ctrl & 0x000f0000) >> 16) {
nv_mask(priv, oreg, mask, oval); case 6: datarate = pclk * 30 / 8; break;
case 5: datarate = pclk * 24 / 8; break;
case 2:
default:
datarate = pclk * 18 / 8;
break;
}
if (nvkm_output_dp_train(outp, datarate / soff, true))
ERR("link not trained before attach\n");
} }
exec_clkcmp(priv, head, 0, pclk, &conf);
if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
oval = 0x00000000;
hval = 0x00000000;
mask = 0xffffffff;
} else
if (!outp->info.location) {
if (outp->info.type == DCB_OUTPUT_DP)
nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
hval = 0x00000000;
mask = 0x00000707;
} else {
oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
oval = 0x00000001;
hval = 0x00000001;
mask = 0x00000707;
}
nv_mask(priv, hreg, 0x0000000f, hval);
nv_mask(priv, oreg, mask, oval);
} }
/* If programming a TMDS output on a SOR that can also be configured for /* If programming a TMDS output on a SOR that can also be configured for
...@@ -1521,30 +1579,16 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp ...@@ -1521,30 +1579,16 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp
static void static void
nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
{ {
struct dcb_output outp; struct nvkm_output *outp;
u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
if (exec_clkcmp(priv, head, 1, pclk, &outp) != ~0) { u32 conf;
if (outp.location == 0 && outp.type == DCB_OUTPUT_TMDS)
nv50_disp_intr_unk40_0_tmds(priv, &outp);
else
if (outp.location == 1 && outp.type == DCB_OUTPUT_DP) {
u32 soff = (ffs(outp.or) - 1) * 0x08;
u32 ctrl = nv_rd32(priv, 0x610b84 + soff);
u32 datarate;
switch ((ctrl & 0x000f0000) >> 16) {
case 6: datarate = pclk * 30 / 8; break;
case 5: datarate = pclk * 24 / 8; break;
case 2:
default:
datarate = pclk * 18 / 8;
break;
}
nouveau_dp_train(&priv->base, priv->pior.dp, outp = exec_clkcmp(priv, head, 1, pclk, &conf);
&outp, head, datarate); if (!outp)
} return;
}
if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
} }
void void
...@@ -1610,13 +1654,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev) ...@@ -1610,13 +1654,13 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
} }
if (intr1 & 0x00000004) { if (intr1 & 0x00000004) {
nouveau_event_trigger(priv->base.vblank, 0); nouveau_event_trigger(priv->base.vblank, 1, 0);
nv_wr32(priv, 0x610024, 0x00000004); nv_wr32(priv, 0x610024, 0x00000004);
intr1 &= ~0x00000004; intr1 &= ~0x00000004;
} }
if (intr1 & 0x00000008) { if (intr1 & 0x00000008) {
nouveau_event_trigger(priv->base.vblank, 1); nouveau_event_trigger(priv->base.vblank, 1, 1);
nv_wr32(priv, 0x610024, 0x00000008); nv_wr32(priv, 0x610024, 0x00000008);
intr1 &= ~0x00000008; intr1 &= ~0x00000008;
} }
...@@ -1656,10 +1700,15 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1656,10 +1700,15 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.sense = nv50_dac_sense; priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
struct nouveau_oclass *
nv50_disp_outp_sclass[] = {
&nv50_pior_dp_impl.base.base,
NULL
};
struct nouveau_oclass * struct nouveau_oclass *
nv50_disp_oclass = &(struct nv50_disp_impl) { nv50_disp_oclass = &(struct nv50_disp_impl) {
.base.base.handle = NV_ENGINE(DISP, 0x50), .base.base.handle = NV_ENGINE(DISP, 0x50),
...@@ -1669,6 +1718,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { ...@@ -1669,6 +1718,7 @@ nv50_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv50_disp_mast_mthd_chan, .mthd.core = &nv50_disp_mast_mthd_chan,
.mthd.base = &nv50_disp_sync_mthd_chan, .mthd.base = &nv50_disp_sync_mthd_chan,
.mthd.ovly = &nv50_disp_ovly_mthd_chan, .mthd.ovly = &nv50_disp_ovly_mthd_chan,
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "dport.h" #include "dport.h"
#include "priv.h" #include "priv.h"
#include "outp.h"
#include "outpdp.h"
struct nv50_disp_impl { struct nv50_disp_impl {
struct nouveau_disp_impl base; struct nouveau_disp_impl base;
...@@ -43,13 +45,11 @@ struct nv50_disp_priv { ...@@ -43,13 +45,11 @@ struct nv50_disp_priv {
int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32); int (*hda_eld)(struct nv50_disp_priv *, int sor, u8 *, u32);
int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32); int (*hdmi)(struct nv50_disp_priv *, int head, int sor, u32);
u32 lvdsconf; u32 lvdsconf;
const struct nouveau_dp_func *dp;
} sor; } sor;
struct { struct {
int nr; int nr;
int (*power)(struct nv50_disp_priv *, int ext, u32 data); int (*power)(struct nv50_disp_priv *, int ext, u32 data);
u8 type[3]; u8 type[3];
const struct nouveau_dp_func *dp;
} pior; } pior;
}; };
...@@ -199,4 +199,14 @@ void nvd0_disp_intr(struct nouveau_subdev *); ...@@ -199,4 +199,14 @@ void nvd0_disp_intr(struct nouveau_subdev *);
extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; extern const struct nv50_disp_mthd_chan nve0_disp_mast_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 nouveau_oclass *nv50_disp_outp_sclass[];
extern struct nvkm_output_dp_impl nv94_sor_dp_impl;
int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
extern struct nouveau_oclass *nv94_disp_outp_sclass[];
extern struct nvkm_output_dp_impl nvd0_sor_dp_impl;
extern struct nouveau_oclass *nvd0_disp_outp_sclass[];
#endif #endif
...@@ -264,7 +264,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -264,7 +264,6 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl; priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
...@@ -277,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) { ...@@ -277,6 +276,7 @@ nv84_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan, .mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
......
...@@ -77,6 +77,7 @@ nv94_disp_base_omthds[] = { ...@@ -77,6 +77,7 @@ nv94_disp_base_omthds[] = {
{ SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
...@@ -122,12 +123,17 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -122,12 +123,17 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.sense = nv50_dac_sense; priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl; priv->sor.hdmi = nv84_hdmi_ctrl;
priv->sor.dp = &nv94_sor_dp_func;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
struct nouveau_oclass *
nv94_disp_outp_sclass[] = {
&nv50_pior_dp_impl.base.base,
&nv94_sor_dp_impl.base.base,
NULL
};
struct nouveau_oclass * struct nouveau_oclass *
nv94_disp_oclass = &(struct nv50_disp_impl) { nv94_disp_oclass = &(struct nv50_disp_impl) {
.base.base.handle = NV_ENGINE(DISP, 0x88), .base.base.handle = NV_ENGINE(DISP, 0x88),
...@@ -137,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) { ...@@ -137,6 +143,7 @@ nv94_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan, .mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
......
...@@ -126,7 +126,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -126,7 +126,6 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hdmi = nv84_hdmi_ctrl; priv->sor.hdmi = nv84_hdmi_ctrl;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
...@@ -139,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -139,6 +138,7 @@ nva0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nv50_disp_outp_sclass,
.mthd.core = &nv84_disp_mast_mthd_chan, .mthd.core = &nv84_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nva0_disp_ovly_mthd_chan, .mthd.ovly = &nva0_disp_ovly_mthd_chan,
......
...@@ -50,6 +50,7 @@ nva3_disp_base_omthds[] = { ...@@ -50,6 +50,7 @@ nva3_disp_base_omthds[] = {
{ SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
...@@ -96,9 +97,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -96,9 +97,7 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nva3_hda_eld; priv->sor.hda_eld = nva3_hda_eld;
priv->sor.hdmi = nva3_hdmi_ctrl; priv->sor.hdmi = nva3_hdmi_ctrl;
priv->sor.dp = &nv94_sor_dp_func;
priv->pior.power = nv50_pior_power; priv->pior.power = nv50_pior_power;
priv->pior.dp = &nv50_pior_dp_func;
return 0; return 0;
} }
...@@ -111,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) { ...@@ -111,6 +110,7 @@ nva3_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nv94_disp_outp_sclass,
.mthd.core = &nv94_disp_mast_mthd_chan, .mthd.core = &nv94_disp_mast_mthd_chan,
.mthd.base = &nv84_disp_sync_mthd_chan, .mthd.base = &nv84_disp_sync_mthd_chan,
.mthd.ovly = &nv84_disp_ovly_mthd_chan, .mthd.ovly = &nv84_disp_ovly_mthd_chan,
......
...@@ -748,13 +748,13 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd, ...@@ -748,13 +748,13 @@ nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
} }
static void static void
nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head) nvd0_disp_base_vblank_enable(struct nouveau_event *event, int type, int head)
{ {
nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
} }
static void static void
nvd0_disp_base_vblank_disable(struct nouveau_event *event, int head) nvd0_disp_base_vblank_disable(struct nouveau_event *event, int type, int head)
{ {
nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); nv_mask(event->priv, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
} }
...@@ -887,6 +887,7 @@ nvd0_disp_base_omthds[] = { ...@@ -887,6 +887,7 @@ nvd0_disp_base_omthds[] = {
{ SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd }, { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD) , nv50_sor_mthd },
{ SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd }, { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR) , nv50_sor_mthd },
{ SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd }, { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
{ SOR_MTHD(NV94_DISP_SOR_DP_PWR) , nv50_sor_mthd },
{ DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_PWR) , nv50_dac_mthd },
{ DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd }, { DAC_MTHD(NV50_DISP_DAC_LOAD) , nv50_dac_mthd },
{ PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd }, { PIOR_MTHD(NV50_DISP_PIOR_PWR) , nv50_pior_mthd },
...@@ -915,19 +916,20 @@ nvd0_disp_sclass[] = { ...@@ -915,19 +916,20 @@ nvd0_disp_sclass[] = {
* Display engine implementation * Display engine implementation
******************************************************************************/ ******************************************************************************/
static u16 static struct nvkm_output *
exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
struct dcb_output *dcb, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_outp *info) struct nvbios_outp *info)
{ {
struct nouveau_bios *bios = nouveau_bios(priv); struct nouveau_bios *bios = nouveau_bios(priv);
u16 mask, type, data; struct nvkm_output *outp;
u16 mask, type;
if (outp < 4) { if (or < 4) {
type = DCB_OUTPUT_ANALOG; type = DCB_OUTPUT_ANALOG;
mask = 0; mask = 0;
} else { } else {
outp -= 4; or -= 4;
switch (ctrl & 0x00000f00) { switch (ctrl & 0x00000f00) {
case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
...@@ -939,101 +941,106 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl, ...@@ -939,101 +941,106 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int outp, u32 ctrl,
nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
return 0x0000; return 0x0000;
} }
dcb->sorconf.link = mask;
} }
mask = 0x00c0 & (mask << 6); mask = 0x00c0 & (mask << 6);
mask |= 0x0001 << outp; mask |= 0x0001 << or;
mask |= 0x0100 << head; mask |= 0x0100 << head;
data = dcb_outp_match(bios, type, mask, ver, hdr, dcb); list_for_each_entry(outp, &priv->base.outp, head) {
if (!data) if ((outp->info.hasht & 0xff) == type &&
return 0x0000; (outp->info.hashm & mask) == mask) {
*data = nvbios_outp_match(bios, outp->info.hasht,
outp->info.hashm,
ver, hdr, cnt, len, info);
if (!*data)
return NULL;
return outp;
}
}
return nvbios_outp_match(bios, type, mask, ver, hdr, cnt, len, info); return NULL;
} }
static bool static struct nvkm_output *
exec_script(struct nv50_disp_priv *priv, int head, int id) exec_script(struct nv50_disp_priv *priv, int head, int id)
{ {
struct nouveau_bios *bios = nouveau_bios(priv); struct nouveau_bios *bios = nouveau_bios(priv);
struct nvkm_output *outp;
struct nvbios_outp info; struct nvbios_outp info;
struct dcb_output dcb;
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
u32 ctrl = 0x00000000; u32 data, ctrl = 0;
u16 data; int or;
int outp;
for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
ctrl = nv_rd32(priv, 0x640180 + (outp * 0x20)); ctrl = nv_rd32(priv, 0x640180 + (or * 0x20));
if (ctrl & (1 << head)) if (ctrl & (1 << head))
break; break;
} }
if (outp == 8) if (or == 8)
return false; return NULL;
data = exec_lookup(priv, head, outp, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info); outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
if (data) { if (outp) {
struct nvbios_init init = { struct nvbios_init init = {
.subdev = nv_subdev(priv), .subdev = nv_subdev(priv),
.bios = bios, .bios = bios,
.offset = info.script[id], .offset = info.script[id],
.outp = &dcb, .outp = &outp->info,
.crtc = head, .crtc = head,
.execute = 1, .execute = 1,
}; };
return nvbios_exec(&init) == 0; nvbios_exec(&init);
} }
return false; return outp;
} }
static u32 static struct nvkm_output *
exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
u32 pclk, struct dcb_output *dcb)
{ {
struct nouveau_bios *bios = nouveau_bios(priv); struct nouveau_bios *bios = nouveau_bios(priv);
struct nvkm_output *outp;
struct nvbios_outp info1; struct nvbios_outp info1;
struct nvbios_ocfg info2; struct nvbios_ocfg info2;
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
u32 ctrl = 0x00000000; u32 data, ctrl = 0;
u32 data, conf = ~0; int or;
int outp;
for (outp = 0; !(ctrl & (1 << head)) && outp < 8; outp++) { for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
ctrl = nv_rd32(priv, 0x660180 + (outp * 0x20)); ctrl = nv_rd32(priv, 0x660180 + (or * 0x20));
if (ctrl & (1 << head)) if (ctrl & (1 << head))
break; break;
} }
if (outp == 8) if (or == 8)
return conf; return NULL;
data = exec_lookup(priv, head, outp, ctrl, dcb, &ver, &hdr, &cnt, &len, &info1); outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
if (data == 0x0000) if (!outp)
return conf; return NULL;
switch (dcb->type) { switch (outp->info.type) {
case DCB_OUTPUT_TMDS: case DCB_OUTPUT_TMDS:
conf = (ctrl & 0x00000f00) >> 8; *conf = (ctrl & 0x00000f00) >> 8;
if (pclk >= 165000) if (pclk >= 165000)
conf |= 0x0100; *conf |= 0x0100;
break; break;
case DCB_OUTPUT_LVDS: case DCB_OUTPUT_LVDS:
conf = priv->sor.lvdsconf; *conf = priv->sor.lvdsconf;
break; break;
case DCB_OUTPUT_DP: case DCB_OUTPUT_DP:
conf = (ctrl & 0x00000f00) >> 8; *conf = (ctrl & 0x00000f00) >> 8;
break; break;
case DCB_OUTPUT_ANALOG: case DCB_OUTPUT_ANALOG:
default: default:
conf = 0x00ff; *conf = 0x00ff;
break; break;
} }
data = nvbios_ocfg_match(bios, data, conf, &ver, &hdr, &cnt, &len, &info2); data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
if (data && id < 0xff) { if (data && id < 0xff) {
data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
if (data) { if (data) {
...@@ -1041,7 +1048,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, ...@@ -1041,7 +1048,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id,
.subdev = nv_subdev(priv), .subdev = nv_subdev(priv),
.bios = bios, .bios = bios,
.offset = data, .offset = data,
.outp = dcb, .outp = &outp->info,
.crtc = head, .crtc = head,
.execute = 1, .execute = 1,
}; };
...@@ -1050,7 +1057,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, ...@@ -1050,7 +1057,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id,
} }
} }
return conf; return outp;
} }
static void static void
...@@ -1062,7 +1069,23 @@ nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head) ...@@ -1062,7 +1069,23 @@ nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
static void static void
nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head) nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
{ {
exec_script(priv, head, 2); struct nvkm_output *outp = exec_script(priv, head, 2);
/* see note in nv50_disp_intr_unk20_0() */
if (outp && outp->info.type == DCB_OUTPUT_DP) {
struct nvkm_output_dp *outpdp = (void *)outp;
struct nvbios_init init = {
.subdev = nv_subdev(priv),
.bios = nouveau_bios(priv),
.outp = &outp->info,
.crtc = head,
.offset = outpdp->info.script[4],
.execute = 1,
};
nvbios_exec(&init);
atomic_set(&outpdp->lt.done, 0);
}
} }
static void static void
...@@ -1124,49 +1147,52 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, ...@@ -1124,49 +1147,52 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
static void static void
nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
{ {
struct dcb_output outp; struct nvkm_output *outp;
u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp); u32 conf, addr, data;
if (conf != ~0) {
u32 addr, data; outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
if (!outp)
if (outp.type == DCB_OUTPUT_DP) { return;
u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
switch ((sync & 0x000003c0) >> 6) { /* see note in nv50_disp_intr_unk20_2() */
case 6: pclk = pclk * 30 / 8; break; if (outp->info.type == DCB_OUTPUT_DP) {
case 5: pclk = pclk * 24 / 8; break; u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
case 2: switch ((sync & 0x000003c0) >> 6) {
default: case 6: pclk = pclk * 30 / 8; break;
pclk = pclk * 18 / 8; case 5: pclk = pclk * 24 / 8; break;
break; case 2:
} default:
pclk = pclk * 18 / 8;
nouveau_dp_train(&priv->base, priv->sor.dp, break;
&outp, head, pclk);
} }
exec_clkcmp(priv, head, 0, pclk, &outp); if (nvkm_output_dp_train(outp, pclk, true))
ERR("link not trained before attach\n");
}
if (outp.type == DCB_OUTPUT_ANALOG) { exec_clkcmp(priv, head, 0, pclk, &conf);
addr = 0x612280 + (ffs(outp.or) - 1) * 0x800;
data = 0x00000000;
} else {
if (outp.type == DCB_OUTPUT_DP)
nvd0_disp_intr_unk2_2_tu(priv, head, &outp);
addr = 0x612300 + (ffs(outp.or) - 1) * 0x800;
data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
}
nv_mask(priv, addr, 0x00000707, data); if (outp->info.type == DCB_OUTPUT_ANALOG) {
addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
data = 0x00000000;
} 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;
data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
} }
nv_mask(priv, addr, 0x00000707, data);
} }
static void static void
nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head)
{ {
struct dcb_output outp;
u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
exec_clkcmp(priv, head, 1, pclk, &outp); u32 conf;
exec_clkcmp(priv, head, 1, pclk, &conf);
} }
void void
...@@ -1240,7 +1266,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid) ...@@ -1240,7 +1266,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
chid, (mthd & 0x0000ffc), data, mthd, unkn); chid, (mthd & 0x0000ffc), data, mthd, unkn);
if (chid == 0) { if (chid == 0) {
switch (mthd) { switch (mthd & 0xffc) {
case 0x0080: case 0x0080:
nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
impl->mthd.core); impl->mthd.core);
...@@ -1250,7 +1276,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid) ...@@ -1250,7 +1276,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
} }
} else } else
if (chid <= 4) { if (chid <= 4) {
switch (mthd) { switch (mthd & 0xffc) {
case 0x0080: case 0x0080:
nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
impl->mthd.base); impl->mthd.base);
...@@ -1260,7 +1286,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid) ...@@ -1260,7 +1286,7 @@ nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
} }
} else } else
if (chid <= 8) { if (chid <= 8) {
switch (mthd) { switch (mthd & 0xffc) {
case 0x0080: case 0x0080:
nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5, nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5,
impl->mthd.ovly); impl->mthd.ovly);
...@@ -1317,7 +1343,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) ...@@ -1317,7 +1343,7 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
if (mask & intr) { if (mask & intr) {
u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
if (stat & 0x00000001) if (stat & 0x00000001)
nouveau_event_trigger(priv->base.vblank, i); nouveau_event_trigger(priv->base.vblank, 1, i);
nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
nv_rd32(priv, 0x6100c0 + (i * 0x800)); nv_rd32(priv, 0x6100c0 + (i * 0x800));
} }
...@@ -1352,10 +1378,15 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -1352,10 +1378,15 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
struct nouveau_oclass *
nvd0_disp_outp_sclass[] = {
&nvd0_sor_dp_impl.base.base,
NULL
};
struct nouveau_oclass * struct nouveau_oclass *
nvd0_disp_oclass = &(struct nv50_disp_impl) { nvd0_disp_oclass = &(struct nv50_disp_impl) {
.base.base.handle = NV_ENGINE(DISP, 0x90), .base.base.handle = NV_ENGINE(DISP, 0x90),
...@@ -1365,6 +1396,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -1365,6 +1396,7 @@ nvd0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nvd0_disp_mast_mthd_chan, .mthd.core = &nvd0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nvd0_disp_ovly_mthd_chan, .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
......
...@@ -246,7 +246,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -246,7 +246,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
...@@ -259,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -259,6 +258,7 @@ nve0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
......
...@@ -81,7 +81,6 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, ...@@ -81,7 +81,6 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->sor.power = nv50_sor_power; priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld; priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl; priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.dp = &nvd0_sor_dp_func;
return 0; return 0;
} }
...@@ -94,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) { ...@@ -94,6 +93,7 @@ nvf0_disp_oclass = &(struct nv50_disp_impl) {
.init = _nouveau_disp_init, .init = _nouveau_disp_init,
.fini = _nouveau_disp_fini, .fini = _nouveau_disp_fini,
}, },
.base.outp = nvd0_disp_outp_sclass,
.mthd.core = &nve0_disp_mast_mthd_chan, .mthd.core = &nve0_disp_mast_mthd_chan,
.mthd.base = &nvd0_disp_sync_mthd_chan, .mthd.base = &nvd0_disp_sync_mthd_chan,
.mthd.ovly = &nve0_disp_ovly_mthd_chan, .mthd.ovly = &nve0_disp_ovly_mthd_chan,
......
/*
* 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/i2c.h>
#include <subdev/bios.h>
#include <subdev/bios/conn.h>
#include "outp.h"
int
_nvkm_output_fini(struct nouveau_object *object, bool suspend)
{
struct nvkm_output *outp = (void *)object;
nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
return nouveau_object_fini(&outp->base, suspend);
}
int
_nvkm_output_init(struct nouveau_object *object)
{
struct nvkm_output *outp = (void *)object;
int ret = nouveau_object_init(&outp->base);
if (ret == 0)
nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
return 0;
}
void
_nvkm_output_dtor(struct nouveau_object *object)
{
struct nvkm_output *outp = (void *)object;
list_del(&outp->head);
nouveau_object_ref(NULL, (void *)&outp->conn);
nouveau_object_destroy(&outp->base);
}
int
nvkm_output_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
struct dcb_output *dcbE, int index,
int length, void **pobject)
{
struct nouveau_bios *bios = nouveau_bios(engine);
struct nouveau_i2c *i2c = nouveau_i2c(parent);
struct nouveau_disp *disp = (void *)engine;
struct nvbios_connE connE;
struct nvkm_output *outp;
u8 ver, hdr;
u32 data;
int ret;
ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
outp = *pobject;
if (ret)
return ret;
outp->info = *dcbE;
outp->index = index;
DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
dcbE->bus, dcbE->heads);
outp->port = i2c->find(i2c, outp->info.i2c_index);
outp->edid = outp->port;
data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
if (!data) {
DBG("vbios connector data not found\n");
memset(&connE, 0x00, sizeof(connE));
connE.type = DCB_CONNECTOR_NONE;
}
ret = nouveau_object_ctor(parent, engine, nvkm_connector_oclass,
&connE, outp->info.connector,
(struct nouveau_object **)&outp->conn);
if (ret < 0) {
ERR("error %d creating connector, disabling\n", ret);
return ret;
}
list_add_tail(&outp->head, &disp->outp);
return 0;
}
int
_nvkm_output_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *dcbE, u32 index,
struct nouveau_object **pobject)
{
struct nvkm_output *outp;
int ret;
ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
*pobject = nv_object(outp);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass *
nvkm_output_oclass = &(struct nvkm_output_impl) {
.base = {
.handle = 0,
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nvkm_output_ctor,
.dtor = _nvkm_output_dtor,
.init = _nvkm_output_init,
.fini = _nvkm_output_fini,
},
},
}.base;
#ifndef __NVKM_DISP_OUTP_H__
#define __NVKM_DISP_OUTP_H__
#include "priv.h"
struct nvkm_output {
struct nouveau_object base;
struct list_head head;
struct dcb_output info;
int index;
struct nouveau_i2c_port *port;
struct nouveau_i2c_port *edid;
struct nvkm_connector *conn;
};
#define nvkm_output_create(p,e,c,b,i,d) \
nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
#define nvkm_output_destroy(d) ({ \
struct nvkm_output *_outp = (d); \
_nvkm_output_dtor(nv_object(_outp)); \
})
#define nvkm_output_init(d) ({ \
struct nvkm_output *_outp = (d); \
_nvkm_output_init(nv_object(_outp)); \
})
#define nvkm_output_fini(d,s) ({ \
struct nvkm_output *_outp = (d); \
_nvkm_output_fini(nv_object(_outp), (s)); \
})
int nvkm_output_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, struct dcb_output *,
int, int, void **);
int _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void _nvkm_output_dtor(struct nouveau_object *);
int _nvkm_output_init(struct nouveau_object *);
int _nvkm_output_fini(struct nouveau_object *, bool);
struct nvkm_output_impl {
struct nouveau_oclass base;
};
#ifndef MSG
#define MSG(l,f,a...) do { \
struct nvkm_output *_outp = (void *)outp; \
nv_##l(nv_object(outp)->engine, "%02x:%04x:%04x: "f, _outp->index, \
_outp->info.hasht, _outp->info.hashm, ##a); \
} while(0)
#define DBG(f,a...) MSG(debug, f, ##a)
#define ERR(f,a...) MSG(error, f, ##a)
#endif
#endif
/*
* 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/i2c.h>
#include "outpdp.h"
#include "conn.h"
#include "dport.h"
int
nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
{
struct nvkm_output_dp *outp = (void *)base;
bool retrain = true;
u8 link[2], stat[3];
u32 rate;
int ret, i;
/* check that the link is trained at a high enough rate */
ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2);
if (ret) {
DBG("failed to read link config, assuming no sink\n");
goto done;
}
rate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET);
if (rate < ((datarate / 8) * 10)) {
DBG("link not trained at sufficient rate\n");
goto done;
}
/* check that link is still trained */
ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3);
if (ret) {
DBG("failed to read link status, assuming no sink\n");
goto done;
}
if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) {
u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
!(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
DBG("lane %d not equalised\n", lane);
goto done;
}
}
retrain = false;
} else {
DBG("no inter-lane alignment\n");
}
done:
if (retrain || !atomic_read(&outp->lt.done)) {
/* no sink, but still need to configure source */
if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) {
outp->dpcd[DPCD_RC01_MAX_LINK_RATE] =
outp->base.info.dpconf.link_bw;
outp->dpcd[DPCD_RC02] =
outp->base.info.dpconf.link_nr;
}
atomic_set(&outp->lt.done, 0);
schedule_work(&outp->lt.work);
} else {
nouveau_event_get(outp->irq);
}
if (wait) {
if (!wait_event_timeout(outp->lt.wait,
atomic_read(&outp->lt.done),
msecs_to_jiffies(2000)))
ret = -ETIMEDOUT;
}
return ret;
}
static void
nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
{
struct nouveau_i2c_port *port = outp->base.edid;
if (present) {
if (!outp->present) {
nouveau_i2c(port)->acquire_pad(port, 0);
DBG("aux power -> always\n");
outp->present = true;
}
nvkm_output_dp_train(&outp->base, 0, true);
} else {
if (outp->present) {
nouveau_i2c(port)->release_pad(port);
DBG("aux power -> demand\n");
outp->present = false;
}
atomic_set(&outp->lt.done, 0);
}
}
static void
nvkm_output_dp_detect(struct nvkm_output_dp *outp)
{
struct nouveau_i2c_port *port = outp->base.edid;
int ret = nouveau_i2c(port)->acquire_pad(port, 0);
if (ret == 0) {
ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV,
outp->dpcd, sizeof(outp->dpcd));
nvkm_output_dp_enable(outp, ret == 0);
nouveau_i2c(port)->release_pad(port);
}
}
static void
nvkm_output_dp_service_work(struct work_struct *work)
{
struct nvkm_output_dp *outp = container_of(work, typeof(*outp), work);
struct nouveau_disp *disp = nouveau_disp(outp);
int type = atomic_xchg(&outp->pending, 0);
u32 send = 0;
if (type & (NVKM_I2C_PLUG | NVKM_I2C_UNPLUG)) {
nvkm_output_dp_detect(outp);
if (type & NVKM_I2C_UNPLUG)
send |= NVKM_HPD_UNPLUG;
if (type & NVKM_I2C_PLUG)
send |= NVKM_HPD_PLUG;
nouveau_event_get(outp->base.conn->hpd.event);
}
if (type & NVKM_I2C_IRQ) {
nvkm_output_dp_train(&outp->base, 0, true);
send |= NVKM_HPD_IRQ;
}
nouveau_event_trigger(disp->hpd, send, outp->base.info.connector);
}
static int
nvkm_output_dp_service(void *data, u32 type, int index)
{
struct nvkm_output_dp *outp = data;
DBG("HPD: %d\n", type);
atomic_or(type, &outp->pending);
schedule_work(&outp->work);
return NVKM_EVENT_DROP;
}
int
_nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
{
struct nvkm_output_dp *outp = (void *)object;
nouveau_event_put(outp->irq);
nvkm_output_dp_enable(outp, false);
return nvkm_output_fini(&outp->base, suspend);
}
int
_nvkm_output_dp_init(struct nouveau_object *object)
{
struct nvkm_output_dp *outp = (void *)object;
nvkm_output_dp_detect(outp);
return nvkm_output_init(&outp->base);
}
void
_nvkm_output_dp_dtor(struct nouveau_object *object)
{
struct nvkm_output_dp *outp = (void *)object;
nouveau_event_ref(NULL, &outp->irq);
nvkm_output_destroy(&outp->base);
}
int
nvkm_output_dp_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
struct dcb_output *info, int index,
int length, void **pobject)
{
struct nouveau_bios *bios = nouveau_bios(parent);
struct nouveau_i2c *i2c = nouveau_i2c(parent);
struct nvkm_output_dp *outp;
u8 hdr, cnt, len;
u32 data;
int ret;
ret = nvkm_output_create_(parent, engine, oclass, info, index,
length, pobject);
outp = *pobject;
if (ret)
return ret;
nouveau_event_ref(NULL, &outp->base.conn->hpd.event);
/* access to the aux channel is not optional... */
if (!outp->base.edid) {
ERR("aux channel not found\n");
return -ENODEV;
}
/* nor is the bios data for this output... */
data = nvbios_dpout_match(bios, outp->base.info.hasht,
outp->base.info.hashm, &outp->version,
&hdr, &cnt, &len, &outp->info);
if (!data) {
ERR("no bios dp data\n");
return -ENODEV;
}
DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len);
/* link training */
INIT_WORK(&outp->lt.work, nouveau_dp_train);
init_waitqueue_head(&outp->lt.wait);
atomic_set(&outp->lt.done, 0);
/* link maintenance */
ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_IRQ, outp->base.edid->index,
nvkm_output_dp_service, outp, &outp->irq);
if (ret) {
ERR("error monitoring aux irq event: %d\n", ret);
return ret;
}
INIT_WORK(&outp->work, nvkm_output_dp_service_work);
/* hotplug detect, replaces gpio-based mechanism with aux events */
ret = nouveau_event_new(i2c->ntfy, NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
outp->base.edid->index,
nvkm_output_dp_service, outp,
&outp->base.conn->hpd.event);
if (ret) {
ERR("error monitoring aux hpd events: %d\n", ret);
return ret;
}
return 0;
}
int
_nvkm_output_dp_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *info, u32 index,
struct nouveau_object **pobject)
{
struct nvkm_output_dp *outp;
int ret;
ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
*pobject = nv_object(outp);
if (ret)
return ret;
return 0;
}
#ifndef __NVKM_DISP_OUTP_DP_H__
#define __NVKM_DISP_OUTP_DP_H__
#include <subdev/bios.h>
#include <subdev/bios/dp.h>
#include "outp.h"
struct nvkm_output_dp {
struct nvkm_output base;
struct nvbios_dpout info;
u8 version;
struct nouveau_eventh *irq;
struct nouveau_eventh *hpd;
struct work_struct work;
atomic_t pending;
bool present;
u8 dpcd[16];
struct {
struct work_struct work;
wait_queue_head_t wait;
atomic_t done;
} lt;
};
#define nvkm_output_dp_create(p,e,c,b,i,d) \
nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
#define nvkm_output_dp_destroy(d) ({ \
struct nvkm_output_dp *_outp = (d); \
_nvkm_output_dp_dtor(nv_object(_outp)); \
})
#define nvkm_output_dp_init(d) ({ \
struct nvkm_output_dp *_outp = (d); \
_nvkm_output_dp_init(nv_object(_outp)); \
})
#define nvkm_output_dp_fini(d,s) ({ \
struct nvkm_output_dp *_outp = (d); \
_nvkm_output_dp_fini(nv_object(_outp), (s)); \
})
int nvkm_output_dp_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, struct dcb_output *,
int, int, void **);
int _nvkm_output_dp_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
void _nvkm_output_dp_dtor(struct nouveau_object *);
int _nvkm_output_dp_init(struct nouveau_object *);
int _nvkm_output_dp_fini(struct nouveau_object *, bool);
struct nvkm_output_dp_impl {
struct nvkm_output_impl base;
int (*pattern)(struct nvkm_output_dp *, int);
int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc);
};
int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
#endif
...@@ -33,68 +33,107 @@ ...@@ -33,68 +33,107 @@
#include "nv50.h" #include "nv50.h"
/****************************************************************************** /******************************************************************************
* DisplayPort * TMDS
*****************************************************************************/ *****************************************************************************/
static struct nouveau_i2c_port *
nv50_pior_dp_find(struct nouveau_disp *disp, struct dcb_output *outp) static int
nv50_pior_tmds_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *info, u32 index,
struct nouveau_object **pobject)
{ {
struct nouveau_i2c *i2c = nouveau_i2c(disp); struct nouveau_i2c *i2c = nouveau_i2c(parent);
return i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(outp->extdev)); struct nvkm_output *outp;
int ret;
ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
*pobject = nv_object(outp);
if (ret)
return ret;
outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
return 0;
} }
struct nvkm_output_impl
nv50_pior_tmds_impl = {
.base.handle = DCB_OUTPUT_TMDS | 0x0100,
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_pior_tmds_ctor,
.dtor = _nvkm_output_dtor,
.init = _nvkm_output_init,
.fini = _nvkm_output_fini,
},
};
/******************************************************************************
* DisplayPort
*****************************************************************************/
static int static int
nv50_pior_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
int head, int pattern)
{ {
struct nouveau_i2c_port *port; struct nouveau_i2c_port *port = outp->base.edid;
int ret = -EINVAL; if (port && port->func->pattern)
return port->func->pattern(port, pattern);
port = nv50_pior_dp_find(disp, outp); return port ? 0 : -ENODEV;
if (port) {
if (port->func->pattern)
ret = port->func->pattern(port, pattern);
else
ret = 0;
}
return ret;
} }
static int static int
nv50_pior_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
int head, int lane_nr, int link_bw, bool enh)
{ {
struct nouveau_i2c_port *port; return 0;
int ret = -EINVAL; }
port = nv50_pior_dp_find(disp, outp); static int
nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
{
struct nouveau_i2c_port *port = outp->base.edid;
if (port && port->func->lnk_ctl) if (port && port->func->lnk_ctl)
ret = port->func->lnk_ctl(port, lane_nr, link_bw, enh); return port->func->lnk_ctl(port, nr, bw, ef);
return port ? 0 : -ENODEV;
}
return ret; static int
nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
{
struct nouveau_i2c_port *port = outp->base.edid;
if (port && port->func->drv_ctl)
return port->func->drv_ctl(port, ln, vs, pe);
return port ? 0 : -ENODEV;
} }
static int static int
nv50_pior_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv50_pior_dp_ctor(struct nouveau_object *parent,
int head, int lane, int vsw, int pre) struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *info, u32 index,
struct nouveau_object **pobject)
{ {
struct nouveau_i2c_port *port; struct nouveau_i2c *i2c = nouveau_i2c(parent);
int ret = -EINVAL; struct nvkm_output_dp *outp;
int ret;
port = nv50_pior_dp_find(disp, outp);
if (port) {
if (port->func->drv_ctl)
ret = port->func->drv_ctl(port, lane, vsw, pre);
else
ret = 0;
}
return ret; ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
*pobject = nv_object(outp);
if (ret)
return ret;
outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(
outp->base.info.extdev));
return 0;
} }
const struct nouveau_dp_func struct nvkm_output_dp_impl
nv50_pior_dp_func = { nv50_pior_dp_impl = {
.base.base.handle = DCB_OUTPUT_DP | 0x0010,
.base.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_pior_dp_ctor,
.dtor = _nvkm_output_dp_dtor,
.init = _nvkm_output_dp_init,
.fini = _nvkm_output_dp_fini,
},
.pattern = nv50_pior_dp_pattern, .pattern = nv50_pior_dp_pattern,
.lnk_pwr = nv50_pior_dp_lnk_pwr,
.lnk_ctl = nv50_pior_dp_lnk_ctl, .lnk_ctl = nv50_pior_dp_lnk_ctl,
.drv_ctl = nv50_pior_dp_drv_ctl, .drv_ctl = nv50_pior_dp_drv_ctl,
}; };
...@@ -102,6 +141,7 @@ nv50_pior_dp_func = { ...@@ -102,6 +141,7 @@ nv50_pior_dp_func = {
/****************************************************************************** /******************************************************************************
* General PIOR handling * General PIOR handling
*****************************************************************************/ *****************************************************************************/
int int
nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data) nv50_pior_power(struct nv50_disp_priv *priv, int or, u32 data)
{ {
......
#ifndef __NVKM_DISP_PRIV_H__ #ifndef __NVKM_DISP_PRIV_H__
#define __NVKM_DISP_PRIV_H__ #define __NVKM_DISP_PRIV_H__
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/conn.h>
#include <engine/disp.h> #include <engine/disp.h>
struct nouveau_disp_impl { struct nouveau_disp_impl {
struct nouveau_oclass base; struct nouveau_oclass base;
struct nouveau_oclass **outp;
struct nouveau_oclass **conn;
}; };
#define nouveau_disp_create(p,e,c,h,i,x,d) \
nouveau_disp_create_((p), (e), (c), (h), (i), (x), \
sizeof(**d), (void **)d)
#define nouveau_disp_destroy(d) ({ \
struct nouveau_disp *disp = (d); \
_nouveau_disp_dtor(nv_object(disp)); \
})
#define nouveau_disp_init(d) ({ \
struct nouveau_disp *disp = (d); \
_nouveau_disp_init(nv_object(disp)); \
})
#define nouveau_disp_fini(d,s) ({ \
struct nouveau_disp *disp = (d); \
_nouveau_disp_fini(nv_object(disp), (s)); \
})
int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int heads,
const char *, const char *, int, void **);
void _nouveau_disp_dtor(struct nouveau_object *);
int _nouveau_disp_init(struct nouveau_object *);
int _nouveau_disp_fini(struct nouveau_object *, bool);
extern struct nouveau_oclass *nvkm_output_oclass;
extern struct nouveau_oclass *nvkm_connector_oclass;
#endif #endif
...@@ -47,8 +47,12 @@ int ...@@ -47,8 +47,12 @@ int
nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
{ {
struct nv50_disp_priv *priv = (void *)object->engine; struct nv50_disp_priv *priv = (void *)object->engine;
const u8 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3; const u8 head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
const u8 link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR); const u8 or = (mthd & NV50_DISP_SOR_MTHD_OR);
const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
struct nvkm_output *outp = NULL, *temp;
u32 data; u32 data;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -56,6 +60,13 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) ...@@ -56,6 +60,13 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
return -EINVAL; return -EINVAL;
data = *(u32 *)args; data = *(u32 *)args;
list_for_each_entry(temp, &priv->base.outp, head) {
if ((temp->info.hasht & 0xff) == type &&
(temp->info.hashm & mask) == mask) {
outp = temp;
break;
}
}
switch (mthd & ~0x3f) { switch (mthd & ~0x3f) {
case NV50_DISP_SOR_PWR: case NV50_DISP_SOR_PWR:
...@@ -71,6 +82,23 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size) ...@@ -71,6 +82,23 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID; priv->sor.lvdsconf = data & NV50_DISP_SOR_LVDS_SCRIPT_ID;
ret = 0; ret = 0;
break; break;
case NV94_DISP_SOR_DP_PWR:
if (outp) {
struct nvkm_output_dp *outpdp = (void *)outp;
switch (data) {
case NV94_DISP_SOR_DP_PWR_STATE_OFF:
((struct nvkm_output_dp_impl *)nv_oclass(outp))
->lnk_pwr(outpdp, 0);
atomic_set(&outpdp->lt.done, 0);
break;
case NV94_DISP_SOR_DP_PWR_STATE_ON:
nvkm_output_dp_train(&outpdp->base, 0, true);
break;
default:
return -EINVAL;
}
}
break;
default: default:
BUG_ON(1); BUG_ON(1);
} }
......
...@@ -29,19 +29,21 @@ ...@@ -29,19 +29,21 @@
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
#include <subdev/bios/dp.h> #include <subdev/bios/dp.h>
#include <subdev/bios/init.h> #include <subdev/bios/init.h>
#include <subdev/timer.h>
#include "nv50.h" #include "nv50.h"
#include "outpdp.h"
static inline u32 static inline u32
nv94_sor_soff(struct dcb_output *outp) nv94_sor_soff(struct nvkm_output_dp *outp)
{ {
return (ffs(outp->or) - 1) * 0x800; return (ffs(outp->base.info.or) - 1) * 0x800;
} }
static inline u32 static inline u32
nv94_sor_loff(struct dcb_output *outp) nv94_sor_loff(struct nvkm_output_dp *outp)
{ {
return nv94_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; return nv94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
} }
static inline u32 static inline u32
...@@ -55,77 +57,96 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) ...@@ -55,77 +57,96 @@ nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
} }
static int static int
nv94_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
int head, int pattern)
{ {
struct nv50_disp_priv *priv = (void *)disp; struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 loff = nv94_sor_loff(outp); const u32 loff = nv94_sor_loff(outp);
nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
return 0; return 0;
} }
int
nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
{
struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 soff = nv94_sor_soff(outp);
const u32 loff = nv94_sor_loff(outp);
u32 mask = 0, i;
for (i = 0; i < nr; i++)
mask |= 1 << (nv94_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 static int
nv94_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
int head, int link_nr, int link_bw, bool enh_frame)
{ {
struct nv50_disp_priv *priv = (void *)disp; struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 soff = nv94_sor_soff(outp); const u32 soff = nv94_sor_soff(outp);
const u32 loff = nv94_sor_loff(outp); const u32 loff = nv94_sor_loff(outp);
u32 dpctrl = 0x00000000; u32 dpctrl = 0x00000000;
u32 clksor = 0x00000000; u32 clksor = 0x00000000;
u32 lane = 0;
int i;
dpctrl |= ((1 << link_nr) - 1) << 16; dpctrl |= ((1 << nr) - 1) << 16;
if (enh_frame) if (ef)
dpctrl |= 0x00004000; dpctrl |= 0x00004000;
if (link_bw > 0x06) if (bw > 0x06)
clksor |= 0x00040000; clksor |= 0x00040000;
for (i = 0; i < link_nr; i++)
lane |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3);
nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor); nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane);
return 0; return 0;
} }
static int static int
nv94_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
int head, int lane, int swing, int preem)
{ {
struct nouveau_bios *bios = nouveau_bios(disp); struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
struct nv50_disp_priv *priv = (void *)disp; struct nouveau_bios *bios = nouveau_bios(priv);
const u32 shift = nv94_sor_dp_lane_map(priv, lane); const u32 shift = nv94_sor_dp_lane_map(priv, ln);
const u32 loff = nv94_sor_loff(outp); const u32 loff = nv94_sor_loff(outp);
u32 addr, data[3]; u32 addr, data[3];
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
struct nvbios_dpout info; struct nvbios_dpout info;
struct nvbios_dpcfg ocfg; struct nvbios_dpcfg ocfg;
addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, addr = nvbios_dpout_match(bios, outp->base.info.hasht,
outp->base.info.hashm,
&ver, &hdr, &cnt, &len, &info); &ver, &hdr, &cnt, &len, &info);
if (!addr) if (!addr)
return -ENODEV; return -ENODEV;
addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
&ver, &hdr, &cnt, &len, &ocfg); &ver, &hdr, &cnt, &len, &ocfg);
if (!addr) if (!addr)
return -EINVAL; return -EINVAL;
data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
data[2] = nv_rd32(priv, 0x61c130 + loff) & ~(0x0000ff00); data[2] = nv_rd32(priv, 0x61c130 + loff);
nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.drv << shift)); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pre << shift)); data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.unk << 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));
return 0; return 0;
} }
const struct nouveau_dp_func struct nvkm_output_dp_impl
nv94_sor_dp_func = { nv94_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 = nv94_sor_dp_pattern, .pattern = nv94_sor_dp_pattern,
.lnk_pwr = nv94_sor_dp_lnk_pwr,
.lnk_ctl = nv94_sor_dp_lnk_ctl, .lnk_ctl = nv94_sor_dp_lnk_ctl,
.drv_ctl = nv94_sor_dp_drv_ctl, .drv_ctl = nv94_sor_dp_drv_ctl,
}; };
...@@ -29,19 +29,20 @@ ...@@ -29,19 +29,20 @@
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
#include <subdev/bios/dp.h> #include <subdev/bios/dp.h>
#include <subdev/bios/init.h> #include <subdev/bios/init.h>
#include <subdev/timer.h>
#include "nv50.h" #include "nv50.h"
static inline u32 static inline u32
nvd0_sor_soff(struct dcb_output *outp) nvd0_sor_soff(struct nvkm_output_dp *outp)
{ {
return (ffs(outp->or) - 1) * 0x800; return (ffs(outp->base.info.or) - 1) * 0x800;
} }
static inline u32 static inline u32
nvd0_sor_loff(struct dcb_output *outp) nvd0_sor_loff(struct nvkm_output_dp *outp)
{ {
return nvd0_sor_soff(outp) + !(outp->sorconf.link & 1) * 0x80; return nvd0_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
} }
static inline u32 static inline u32
...@@ -52,77 +53,80 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) ...@@ -52,77 +53,80 @@ nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
} }
static int static int
nvd0_sor_dp_pattern(struct nouveau_disp *disp, struct dcb_output *outp, nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
int head, int pattern)
{ {
struct nv50_disp_priv *priv = (void *)disp; struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 loff = nvd0_sor_loff(outp); const u32 loff = nvd0_sor_loff(outp);
nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
return 0; return 0;
} }
static int static int
nvd0_sor_dp_lnk_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
int head, int link_nr, int link_bw, bool enh_frame)
{ {
struct nv50_disp_priv *priv = (void *)disp; struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
const u32 soff = nvd0_sor_soff(outp); const u32 soff = nvd0_sor_soff(outp);
const u32 loff = nvd0_sor_loff(outp); const u32 loff = nvd0_sor_loff(outp);
u32 dpctrl = 0x00000000; u32 dpctrl = 0x00000000;
u32 clksor = 0x00000000; u32 clksor = 0x00000000;
u32 lane = 0;
int i;
clksor |= link_bw << 18; clksor |= bw << 18;
dpctrl |= ((1 << link_nr) - 1) << 16; dpctrl |= ((1 << nr) - 1) << 16;
if (enh_frame) if (ef)
dpctrl |= 0x00004000; dpctrl |= 0x00004000;
for (i = 0; i < link_nr; i++)
lane |= 1 << (nvd0_sor_dp_lane_map(priv, i) >> 3);
nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor); nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
nv_mask(priv, 0x61c130 + loff, 0x0000000f, lane);
return 0; return 0;
} }
static int static int
nvd0_sor_dp_drv_ctl(struct nouveau_disp *disp, struct dcb_output *outp, nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
int head, int lane, int swing, int preem)
{ {
struct nouveau_bios *bios = nouveau_bios(disp); struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
struct nv50_disp_priv *priv = (void *)disp; struct nouveau_bios *bios = nouveau_bios(priv);
const u32 shift = nvd0_sor_dp_lane_map(priv, lane); const u32 shift = nvd0_sor_dp_lane_map(priv, ln);
const u32 loff = nvd0_sor_loff(outp); const u32 loff = nvd0_sor_loff(outp);
u32 addr, data[3]; u32 addr, data[4];
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
struct nvbios_dpout info; struct nvbios_dpout info;
struct nvbios_dpcfg ocfg; struct nvbios_dpcfg ocfg;
addr = nvbios_dpout_match(bios, outp->hasht, outp->hashm, addr = nvbios_dpout_match(bios, outp->base.info.hasht,
outp->base.info.hashm,
&ver, &hdr, &cnt, &len, &info); &ver, &hdr, &cnt, &len, &info);
if (!addr) if (!addr)
return -ENODEV; return -ENODEV;
addr = nvbios_dpcfg_match(bios, addr, 0, swing, preem, addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
&ver, &hdr, &cnt, &len, &ocfg); &ver, &hdr, &cnt, &len, &ocfg);
if (!addr) if (!addr)
return -EINVAL; return -EINVAL;
data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
data[2] = nv_rd32(priv, 0x61c130 + loff) & ~(0x0000ff00); data[2] = nv_rd32(priv, 0x61c130 + loff);
nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.drv << shift)); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pre << shift)); data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.unk << 8)); nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
nv_mask(priv, 0x61c13c + loff, 0x00000000, 0x00000000); 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; return 0;
} }
const struct nouveau_dp_func struct nvkm_output_dp_impl
nvd0_sor_dp_func = { nvd0_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 = nvd0_sor_dp_pattern, .pattern = nvd0_sor_dp_pattern,
.lnk_pwr = nv94_sor_dp_lnk_pwr,
.lnk_ctl = nvd0_sor_dp_lnk_ctl, .lnk_ctl = nvd0_sor_dp_lnk_ctl,
.drv_ctl = nvd0_sor_dp_drv_ctl, .drv_ctl = nvd0_sor_dp_drv_ctl,
}; };
...@@ -91,7 +91,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent, ...@@ -91,7 +91,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
if (!chan->user) if (!chan->user)
return -EFAULT; return -EFAULT;
nouveau_event_trigger(priv->cevent, 0); nouveau_event_trigger(priv->cevent, 1, 0);
chan->size = size; chan->size = size;
return 0; return 0;
...@@ -194,11 +194,11 @@ nouveau_fifo_create_(struct nouveau_object *parent, ...@@ -194,11 +194,11 @@ nouveau_fifo_create_(struct nouveau_object *parent,
if (!priv->channel) if (!priv->channel)
return -ENOMEM; return -ENOMEM;
ret = nouveau_event_create(1, &priv->cevent); ret = nouveau_event_create(1, 1, &priv->cevent);
if (ret) if (ret)
return ret; return ret;
ret = nouveau_event_create(1, &priv->uevent); ret = nouveau_event_create(1, 1, &priv->uevent);
if (ret) if (ret)
return ret; return ret;
......
...@@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) ...@@ -539,7 +539,7 @@ nv04_fifo_intr(struct nouveau_subdev *subdev)
} }
if (status & 0x40000000) { if (status & 0x40000000) {
nouveau_event_trigger(priv->base.uevent, 0); nouveau_event_trigger(priv->base.uevent, 1, 0);
nv_wr32(priv, 0x002100, 0x40000000); nv_wr32(priv, 0x002100, 0x40000000);
status &= ~0x40000000; status &= ~0x40000000;
} }
......
...@@ -389,14 +389,14 @@ nv84_fifo_cclass = { ...@@ -389,14 +389,14 @@ nv84_fifo_cclass = {
******************************************************************************/ ******************************************************************************/
static void static void
nv84_fifo_uevent_enable(struct nouveau_event *event, int index) nv84_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
{ {
struct nv84_fifo_priv *priv = event->priv; struct nv84_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x40000000, 0x40000000); nv_mask(priv, 0x002140, 0x40000000, 0x40000000);
} }
static void static void
nv84_fifo_uevent_disable(struct nouveau_event *event, int index) nv84_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
{ {
struct nv84_fifo_priv *priv = event->priv; struct nv84_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x40000000, 0x00000000); nv_mask(priv, 0x002140, 0x40000000, 0x00000000);
......
...@@ -730,7 +730,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) ...@@ -730,7 +730,7 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
for (unkn = 0; unkn < 8; unkn++) { for (unkn = 0; unkn < 8; unkn++) {
u32 ints = (intr >> (unkn * 0x04)) & inte; u32 ints = (intr >> (unkn * 0x04)) & inte;
if (ints & 0x1) { if (ints & 0x1) {
nouveau_event_trigger(priv->base.uevent, 0); nouveau_event_trigger(priv->base.uevent, 1, 0);
ints &= ~1; ints &= ~1;
} }
if (ints) { if (ints) {
...@@ -827,14 +827,14 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) ...@@ -827,14 +827,14 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
} }
static void static void
nvc0_fifo_uevent_enable(struct nouveau_event *event, int index) nvc0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
{ {
struct nvc0_fifo_priv *priv = event->priv; struct nvc0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x80000000); nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
} }
static void static void
nvc0_fifo_uevent_disable(struct nouveau_event *event, int index) nvc0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
{ {
struct nvc0_fifo_priv *priv = event->priv; struct nvc0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x00000000); nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
......
...@@ -859,7 +859,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv) ...@@ -859,7 +859,7 @@ nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
static void static void
nve0_fifo_intr_engine(struct nve0_fifo_priv *priv) nve0_fifo_intr_engine(struct nve0_fifo_priv *priv)
{ {
nouveau_event_trigger(priv->base.uevent, 0); nouveau_event_trigger(priv->base.uevent, 1, 0);
} }
static void static void
...@@ -952,14 +952,14 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) ...@@ -952,14 +952,14 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
} }
static void static void
nve0_fifo_uevent_enable(struct nouveau_event *event, int index) nve0_fifo_uevent_enable(struct nouveau_event *event, int type, int index)
{ {
struct nve0_fifo_priv *priv = event->priv; struct nve0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x80000000); nv_mask(priv, 0x002140, 0x80000000, 0x80000000);
} }
static void static void
nve0_fifo_uevent_disable(struct nouveau_event *event, int index) nve0_fifo_uevent_disable(struct nouveau_event *event, int type, int index)
{ {
struct nve0_fifo_priv *priv = event->priv; struct nve0_fifo_priv *priv = event->priv;
nv_mask(priv, 0x002140, 0x80000000, 0x00000000); nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
......
...@@ -124,7 +124,7 @@ nv50_software_sclass[] = { ...@@ -124,7 +124,7 @@ nv50_software_sclass[] = {
******************************************************************************/ ******************************************************************************/
static int static int
nv50_software_vblsem_release(void *data, int head) nv50_software_vblsem_release(void *data, u32 type, int head)
{ {
struct nv50_software_chan *chan = data; struct nv50_software_chan *chan = data;
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
...@@ -183,7 +183,7 @@ nv50_software_context_ctor(struct nouveau_object *parent, ...@@ -183,7 +183,7 @@ nv50_software_context_ctor(struct nouveau_object *parent,
return -ENOMEM; return -ENOMEM;
for (i = 0; i < chan->vblank.nr_event; i++) { for (i = 0; i < chan->vblank.nr_event; i++) {
ret = nouveau_event_new(pdisp->vblank, i, pclass->vblank, ret = nouveau_event_new(pdisp->vblank, 1, i, pclass->vblank,
chan, &chan->vblank.event[i]); chan, &chan->vblank.event[i]);
if (ret) if (ret)
return ret; return ret;
......
...@@ -19,7 +19,7 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *, ...@@ -19,7 +19,7 @@ int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
struct nv50_software_cclass { struct nv50_software_cclass {
struct nouveau_oclass base; struct nouveau_oclass base;
int (*vblank)(void *, int); int (*vblank)(void *, u32, int);
}; };
struct nv50_software_chan { struct nv50_software_chan {
......
...@@ -104,7 +104,7 @@ nvc0_software_sclass[] = { ...@@ -104,7 +104,7 @@ nvc0_software_sclass[] = {
******************************************************************************/ ******************************************************************************/
static int static int
nvc0_software_vblsem_release(void *data, int head) nvc0_software_vblsem_release(void *data, u32 type, int head)
{ {
struct nv50_software_chan *chan = data; struct nv50_software_chan *chan = data;
struct nv50_software_priv *priv = (void *)nv_object(chan)->engine; struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
......
...@@ -295,6 +295,10 @@ struct nv04_display_scanoutpos { ...@@ -295,6 +295,10 @@ struct nv04_display_scanoutpos {
#define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f #define NV84_DISP_SOR_HDMI_PWR_REKEY 0x0000007f
#define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000 #define NV50_DISP_SOR_LVDS_SCRIPT 0x00013000
#define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff #define NV50_DISP_SOR_LVDS_SCRIPT_ID 0x0000ffff
#define NV94_DISP_SOR_DP_PWR 0x00016000
#define NV94_DISP_SOR_DP_PWR_STATE 0x00000001
#define NV94_DISP_SOR_DP_PWR_STATE_OFF 0x00000000
#define NV94_DISP_SOR_DP_PWR_STATE_ON 0x00000001
#define NV50_DISP_DAC_MTHD 0x00020000 #define NV50_DISP_DAC_MTHD 0x00020000
#define NV50_DISP_DAC_MTHD_TYPE 0x0000f000 #define NV50_DISP_DAC_MTHD_TYPE 0x0000f000
......
...@@ -12,32 +12,33 @@ struct nouveau_eventh { ...@@ -12,32 +12,33 @@ struct nouveau_eventh {
struct nouveau_event *event; struct nouveau_event *event;
struct list_head head; struct list_head head;
unsigned long flags; unsigned long flags;
u32 types;
int index; int index;
int (*func)(void *, int); int (*func)(void *, u32, int);
void *priv; void *priv;
}; };
struct nouveau_event { struct nouveau_event {
spinlock_t list_lock;
spinlock_t refs_lock;
void *priv; void *priv;
void (*enable)(struct nouveau_event *, int index); int (*check)(struct nouveau_event *, u32 type, int index);
void (*disable)(struct nouveau_event *, int index); void (*enable)(struct nouveau_event *, int type, int index);
void (*disable)(struct nouveau_event *, int type, int index);
int types_nr;
int index_nr; int index_nr;
struct {
struct list_head list; spinlock_t list_lock;
int refs; struct list_head *list;
} index[]; spinlock_t refs_lock;
int refs[];
}; };
int nouveau_event_create(int index_nr, struct nouveau_event **); int nouveau_event_create(int types_nr, int index_nr, struct nouveau_event **);
void nouveau_event_destroy(struct nouveau_event **); void nouveau_event_destroy(struct nouveau_event **);
void nouveau_event_trigger(struct nouveau_event *, int index); void nouveau_event_trigger(struct nouveau_event *, u32 types, int index);
int nouveau_event_new(struct nouveau_event *, int index, int nouveau_event_new(struct nouveau_event *, u32 types, int index,
int (*func)(void *, int), void *, int (*func)(void *, u32, int), void *,
struct nouveau_eventh **); struct nouveau_eventh **);
void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **); void nouveau_event_ref(struct nouveau_eventh *, struct nouveau_eventh **);
void nouveau_event_get(struct nouveau_eventh *); void nouveau_event_get(struct nouveau_eventh *);
......
...@@ -6,8 +6,19 @@ ...@@ -6,8 +6,19 @@
#include <core/device.h> #include <core/device.h>
#include <core/event.h> #include <core/event.h>
enum nvkm_hpd_event {
NVKM_HPD_PLUG = 1,
NVKM_HPD_UNPLUG = 2,
NVKM_HPD_IRQ = 4,
NVKM_HPD = (NVKM_HPD_PLUG | NVKM_HPD_UNPLUG | NVKM_HPD_IRQ)
};
struct nouveau_disp { struct nouveau_disp {
struct nouveau_engine base; struct nouveau_engine base;
struct list_head outp;
struct nouveau_event *hpd;
struct nouveau_event *vblank; struct nouveau_event *vblank;
}; };
...@@ -17,25 +28,6 @@ nouveau_disp(void *obj) ...@@ -17,25 +28,6 @@ nouveau_disp(void *obj)
return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP]; return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
} }
#define nouveau_disp_create(p,e,c,h,i,x,d) \
nouveau_disp_create_((p), (e), (c), (h), (i), (x), \
sizeof(**d), (void **)d)
#define nouveau_disp_destroy(d) ({ \
struct nouveau_disp *disp = (d); \
_nouveau_disp_dtor(nv_object(disp)); \
})
#define nouveau_disp_init(d) \
nouveau_engine_init(&(d)->base)
#define nouveau_disp_fini(d,s) \
nouveau_engine_fini(&(d)->base, (s))
int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int heads,
const char *, const char *, int, void **);
void _nouveau_disp_dtor(struct nouveau_object *);
#define _nouveau_disp_init _nouveau_engine_init
#define _nouveau_disp_fini _nouveau_engine_fini
extern struct nouveau_oclass *nv04_disp_oclass; extern struct nouveau_oclass *nv04_disp_oclass;
extern struct nouveau_oclass *nv50_disp_oclass; extern struct nouveau_oclass *nv50_disp_oclass;
extern struct nouveau_oclass *nv84_disp_oclass; extern struct nouveau_oclass *nv84_disp_oclass;
......
...@@ -22,7 +22,25 @@ enum dcb_connector_type { ...@@ -22,7 +22,25 @@ enum dcb_connector_type {
DCB_CONNECTOR_NONE = 0xff DCB_CONNECTOR_NONE = 0xff
}; };
u16 dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); struct nvbios_connT {
u16 dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len); };
u32 nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u32 nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_connT *info);
struct nvbios_connE {
u8 type;
u8 location;
u8 hpd;
u8 dp;
u8 di;
u8 sr;
u8 lcdid;
};
u32 nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr);
u32 nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr,
struct nvbios_connE *info);
#endif #endif
...@@ -17,9 +17,10 @@ u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask, ...@@ -17,9 +17,10 @@ u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask,
struct nvbios_dpout *); struct nvbios_dpout *);
struct nvbios_dpcfg { struct nvbios_dpcfg {
u8 drv; u8 pc;
u8 pre; u8 dc;
u8 unk; u8 pe;
u8 tx_pu;
}; };
u16 u16
...@@ -27,7 +28,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx, ...@@ -27,7 +28,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_dpcfg *); struct nvbios_dpcfg *);
u16 u16
nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 un, u8 vs, u8 pe, nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 pc, u8 vs, u8 pe,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_dpcfg *); struct nvbios_dpcfg *);
......
...@@ -8,17 +8,18 @@ ...@@ -8,17 +8,18 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/gpio.h> #include <subdev/bios/gpio.h>
enum nvkm_gpio_event {
NVKM_GPIO_HI = 1,
NVKM_GPIO_LO = 2,
NVKM_GPIO_TOGGLED = (NVKM_GPIO_HI | NVKM_GPIO_LO),
};
struct nouveau_gpio { struct nouveau_gpio {
struct nouveau_subdev base; struct nouveau_subdev base;
struct nouveau_event *events; struct nouveau_event *events;
/* hardware interfaces */
void (*reset)(struct nouveau_gpio *, u8 func); void (*reset)(struct nouveau_gpio *, u8 func);
int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
int (*sense)(struct nouveau_gpio *, int line);
/* software interfaces */
int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
struct dcb_gpio_func *); struct dcb_gpio_func *);
int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state); int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
...@@ -31,23 +32,10 @@ nouveau_gpio(void *obj) ...@@ -31,23 +32,10 @@ nouveau_gpio(void *obj)
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO]; return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO];
} }
#define nouveau_gpio_create(p,e,o,l,d) \ extern struct nouveau_oclass *nv10_gpio_oclass;
nouveau_gpio_create_((p), (e), (o), (l), sizeof(**d), (void **)d) extern struct nouveau_oclass *nv50_gpio_oclass;
#define nouveau_gpio_destroy(p) ({ \ extern struct nouveau_oclass *nv92_gpio_oclass;
struct nouveau_gpio *gpio = (p); \ extern struct nouveau_oclass *nvd0_gpio_oclass;
_nouveau_gpio_dtor(nv_object(gpio)); \ extern struct nouveau_oclass *nve0_gpio_oclass;
})
#define nouveau_gpio_fini(p,s) \
nouveau_subdev_fini(&(p)->base, (s))
int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, int, void **);
void _nouveau_gpio_dtor(struct nouveau_object *);
int nouveau_gpio_init(struct nouveau_gpio *);
extern struct nouveau_oclass nv10_gpio_oclass;
extern struct nouveau_oclass nv50_gpio_oclass;
extern struct nouveau_oclass nvd0_gpio_oclass;
extern struct nouveau_oclass nve0_gpio_oclass;
#endif #endif
...@@ -14,52 +14,41 @@ ...@@ -14,52 +14,41 @@
#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) #define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) #define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
enum nvkm_i2c_event {
NVKM_I2C_PLUG = 1,
NVKM_I2C_UNPLUG = 2,
NVKM_I2C_IRQ = 4,
NVKM_I2C_DONE = 8,
NVKM_I2C_ANY = (NVKM_I2C_PLUG |
NVKM_I2C_UNPLUG |
NVKM_I2C_IRQ |
NVKM_I2C_DONE),
};
struct nouveau_i2c_port { struct nouveau_i2c_port {
struct nouveau_object base; struct nouveau_object base;
struct i2c_adapter adapter; struct i2c_adapter adapter;
struct mutex mutex;
struct list_head head; struct list_head head;
u8 index; u8 index;
int aux;
const struct nouveau_i2c_func *func; const struct nouveau_i2c_func *func;
}; };
struct nouveau_i2c_func { struct nouveau_i2c_func {
void (*acquire)(struct nouveau_i2c_port *);
void (*release)(struct nouveau_i2c_port *);
void (*drive_scl)(struct nouveau_i2c_port *, int); void (*drive_scl)(struct nouveau_i2c_port *, int);
void (*drive_sda)(struct nouveau_i2c_port *, int); void (*drive_sda)(struct nouveau_i2c_port *, int);
int (*sense_scl)(struct nouveau_i2c_port *); int (*sense_scl)(struct nouveau_i2c_port *);
int (*sense_sda)(struct nouveau_i2c_port *); int (*sense_sda)(struct nouveau_i2c_port *);
int (*aux)(struct nouveau_i2c_port *, u8, u32, u8 *, u8); int (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8);
int (*pattern)(struct nouveau_i2c_port *, int pattern); int (*pattern)(struct nouveau_i2c_port *, int pattern);
int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh); int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe); int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
}; };
#define nouveau_i2c_port_create(p,e,o,i,a,f,d) \
nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \
sizeof(**d), (void **)d)
#define nouveau_i2c_port_destroy(p) ({ \
struct nouveau_i2c_port *port = (p); \
_nouveau_i2c_port_dtor(nv_object(i2c)); \
})
#define nouveau_i2c_port_init(p) \
nouveau_object_init(&(p)->base)
#define nouveau_i2c_port_fini(p,s) \
nouveau_object_fini(&(p)->base, (s))
int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, u8,
const struct i2c_algorithm *,
const struct nouveau_i2c_func *,
int, void **);
void _nouveau_i2c_port_dtor(struct nouveau_object *);
#define _nouveau_i2c_port_init nouveau_object_init
#define _nouveau_i2c_port_fini nouveau_object_fini
struct nouveau_i2c_board_info { struct nouveau_i2c_board_info {
struct i2c_board_info dev; struct i2c_board_info dev;
u8 udelay; /* set to 0 to use the standard delay */ u8 udelay; /* set to 0 to use the standard delay */
...@@ -67,13 +56,20 @@ struct nouveau_i2c_board_info { ...@@ -67,13 +56,20 @@ struct nouveau_i2c_board_info {
struct nouveau_i2c { struct nouveau_i2c {
struct nouveau_subdev base; struct nouveau_subdev base;
struct nouveau_event *ntfy;
struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index); struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type); struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
int (*acquire_pad)(struct nouveau_i2c_port *, unsigned long timeout);
void (*release_pad)(struct nouveau_i2c_port *);
int (*acquire)(struct nouveau_i2c_port *, unsigned long timeout);
void (*release)(struct nouveau_i2c_port *);
int (*identify)(struct nouveau_i2c *, int index, int (*identify)(struct nouveau_i2c *, int index,
const char *what, struct nouveau_i2c_board_info *, const char *what, struct nouveau_i2c_board_info *,
bool (*match)(struct nouveau_i2c_port *, bool (*match)(struct nouveau_i2c_port *,
struct i2c_board_info *, void *), void *); struct i2c_board_info *, void *), void *);
wait_queue_head_t wait;
struct list_head ports; struct list_head ports;
}; };
...@@ -83,37 +79,12 @@ nouveau_i2c(void *obj) ...@@ -83,37 +79,12 @@ nouveau_i2c(void *obj)
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C]; return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C];
} }
#define nouveau_i2c_create(p,e,o,s,d) \ extern struct nouveau_oclass *nv04_i2c_oclass;
nouveau_i2c_create_((p), (e), (o), (s), sizeof(**d), (void **)d) extern struct nouveau_oclass *nv4e_i2c_oclass;
#define nouveau_i2c_destroy(p) ({ \ extern struct nouveau_oclass *nv50_i2c_oclass;
struct nouveau_i2c *i2c = (p); \ extern struct nouveau_oclass *nv94_i2c_oclass;
_nouveau_i2c_dtor(nv_object(i2c)); \ extern struct nouveau_oclass *nvd0_i2c_oclass;
}) extern struct nouveau_oclass *nve0_i2c_oclass;
#define nouveau_i2c_init(p) ({ \
struct nouveau_i2c *i2c = (p); \
_nouveau_i2c_init(nv_object(i2c)); \
})
#define nouveau_i2c_fini(p,s) ({ \
struct nouveau_i2c *i2c = (p); \
_nouveau_i2c_fini(nv_object(i2c), (s)); \
})
int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, struct nouveau_oclass *,
int, void **);
void _nouveau_i2c_dtor(struct nouveau_object *);
int _nouveau_i2c_init(struct nouveau_object *);
int _nouveau_i2c_fini(struct nouveau_object *, bool);
extern struct nouveau_oclass nv04_i2c_oclass;
extern struct nouveau_oclass nv4e_i2c_oclass;
extern struct nouveau_oclass nv50_i2c_oclass;
extern struct nouveau_oclass nv94_i2c_oclass;
extern struct nouveau_oclass nvd0_i2c_oclass;
extern struct nouveau_oclass nouveau_anx9805_sclass[];
extern const struct i2c_algorithm nouveau_i2c_bit_algo;
extern const struct i2c_algorithm nouveau_i2c_aux_algo;
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)
......
...@@ -28,12 +28,12 @@ ...@@ -28,12 +28,12 @@
#include <subdev/bios/dcb.h> #include <subdev/bios/dcb.h>
#include <subdev/bios/conn.h> #include <subdev/bios/conn.h>
u16 u32
dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{ {
u16 dcb = dcb_table(bios, ver, hdr, cnt, len); u32 dcb = dcb_table(bios, ver, hdr, cnt, len);
if (dcb && *ver >= 0x30 && *hdr >= 0x16) { if (dcb && *ver >= 0x30 && *hdr >= 0x16) {
u16 data = nv_ro16(bios, dcb + 0x14); u32 data = nv_ro16(bios, dcb + 0x14);
if (data) { if (data) {
*ver = nv_ro08(bios, data + 0); *ver = nv_ro08(bios, data + 0);
*hdr = nv_ro08(bios, data + 1); *hdr = nv_ro08(bios, data + 1);
...@@ -42,15 +42,59 @@ dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) ...@@ -42,15 +42,59 @@ dcb_conntab(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
return data; return data;
} }
} }
return 0x0000; return 0x00000000;
} }
u16 u32
dcb_conn(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len) nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_connT *info)
{
u32 data = nvbios_connTe(bios, ver, hdr, cnt, len);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x30:
case 0x40:
return data;
default:
break;
}
return 0x00000000;
}
u32
nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
{ {
u8 hdr, cnt; u8 hdr, cnt;
u16 data = dcb_conntab(bios, ver, &hdr, &cnt, len); u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len);
if (data && idx < cnt) if (data && idx < cnt)
return data + hdr + (idx * *len); return data + hdr + (idx * *len);
return 0x0000; return 0x00000000;
}
u32
nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
struct nvbios_connE *info)
{
u32 data = nvbios_connEe(bios, idx, ver, len);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x30:
case 0x40:
info->type = nv_ro08(bios, data + 0x00);
info->location = nv_ro08(bios, data + 0x01) & 0x0f;
info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4;
info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6;
if (*len < 4)
return data;
info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2;
info->dp |= nv_ro08(bios, data + 0x02) & 0x0c;
info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4;
info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4;
info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3;
info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4;
return data;
default:
break;
}
return 0x00000000;
} }
...@@ -162,18 +162,20 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, ...@@ -162,18 +162,20 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
struct nvbios_dpcfg *info) struct nvbios_dpcfg *info)
{ {
u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len); u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
memset(info, 0x00, sizeof(*info));
if (data) { if (data) {
switch (*ver) { switch (*ver) {
case 0x21: case 0x21:
info->drv = nv_ro08(bios, data + 0x02); info->dc = nv_ro08(bios, data + 0x02);
info->pre = nv_ro08(bios, data + 0x03); info->pe = nv_ro08(bios, data + 0x03);
info->unk = nv_ro08(bios, data + 0x04); info->tx_pu = nv_ro08(bios, data + 0x04);
break; break;
case 0x30: case 0x30:
case 0x40: case 0x40:
info->drv = nv_ro08(bios, data + 0x01); info->pc = nv_ro08(bios, data + 0x00);
info->pre = nv_ro08(bios, data + 0x02); info->dc = nv_ro08(bios, data + 0x01);
info->unk = nv_ro08(bios, data + 0x03); info->pe = nv_ro08(bios, data + 0x02);
info->tx_pu = nv_ro08(bios, data + 0x03);
break; break;
default: default:
data = 0x0000; data = 0x0000;
...@@ -184,7 +186,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx, ...@@ -184,7 +186,7 @@ nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
} }
u16 u16
nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_dpcfg *info) struct nvbios_dpcfg *info)
{ {
...@@ -193,16 +195,15 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe, ...@@ -193,16 +195,15 @@ nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 un, u8 vs, u8 pe,
if (*ver >= 0x30) { if (*ver >= 0x30) {
const u8 vsoff[] = { 0, 4, 7, 9 }; const u8 vsoff[] = { 0, 4, 7, 9 };
idx = (un * 10) + vsoff[vs] + pe; idx = (pc * 10) + vsoff[vs] + pe;
} else { } else {
while ((data = nvbios_dpcfg_entry(bios, outp, idx, while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
ver, hdr, cnt, len))) { ver, hdr, cnt, len))) {
if (nv_ro08(bios, data + 0x00) == vs && if (nv_ro08(bios, data + 0x00) == vs &&
nv_ro08(bios, data + 0x01) == pe) nv_ro08(bios, data + 0x01) == pe)
break; break;
idx++;
} }
} }
return nvbios_dpcfg_parse(bios, outp, pe, ver, hdr, cnt, len, info); return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
} }
...@@ -98,15 +98,16 @@ static u8 ...@@ -98,15 +98,16 @@ static u8
init_conn(struct nvbios_init *init) init_conn(struct nvbios_init *init)
{ {
struct nouveau_bios *bios = init->bios; struct nouveau_bios *bios = init->bios;
u8 ver, len; struct nvbios_connE connE;
u16 conn; u8 ver, hdr;
u32 conn;
if (init_exec(init)) { if (init_exec(init)) {
if (init->outp) { if (init->outp) {
conn = init->outp->connector; conn = init->outp->connector;
conn = dcb_conn(bios, conn, &ver, &len); conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE);
if (conn) if (conn)
return nv_ro08(bios, conn); return connE.type;
} }
error("script needs connector type\n"); error("script needs connector type\n");
......
...@@ -22,21 +22,24 @@ ...@@ -22,21 +22,24 @@
* Authors: Ben Skeggs * Authors: Ben Skeggs
*/ */
#include <subdev/gpio.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/gpio.h> #include <subdev/bios/gpio.h>
#include "priv.h"
static int static int
nouveau_gpio_drive(struct nouveau_gpio *gpio, nouveau_gpio_drive(struct nouveau_gpio *gpio,
int idx, int line, int dir, int out) int idx, int line, int dir, int out)
{ {
return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV; const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV;
} }
static int static int
nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line) nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line)
{ {
return gpio->sense ? gpio->sense(gpio, line) : -ENODEV; const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
return impl->sense ? impl->sense(gpio, line) : -ENODEV;
} }
static int static int
...@@ -102,6 +105,80 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) ...@@ -102,6 +105,80 @@ nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
return ret; return ret;
} }
static void
nouveau_gpio_intr_disable(struct nouveau_event *event, int type, int index)
{
struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
impl->intr_mask(gpio, type, 1 << index, 0);
}
static void
nouveau_gpio_intr_enable(struct nouveau_event *event, int type, int index)
{
struct nouveau_gpio *gpio = nouveau_gpio(event->priv);
const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
impl->intr_mask(gpio, type, 1 << index, 1 << index);
}
static void
nouveau_gpio_intr(struct nouveau_subdev *subdev)
{
struct nouveau_gpio *gpio = nouveau_gpio(subdev);
const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
u32 hi, lo, e, i;
impl->intr_stat(gpio, &hi, &lo);
for (i = 0; e = 0, (hi | lo) && i < impl->lines; i++) {
if (hi & (1 << i))
e |= NVKM_GPIO_HI;
if (lo & (1 << i))
e |= NVKM_GPIO_LO;
nouveau_event_trigger(gpio->events, e, i);
}
}
int
_nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
{
const struct nouveau_gpio_impl *impl = (void *)object->oclass;
struct nouveau_gpio *gpio = nouveau_gpio(object);
u32 mask = (1 << impl->lines) - 1;
impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
impl->intr_stat(gpio, &mask, &mask);
return nouveau_subdev_fini(&gpio->base, suspend);
}
static struct dmi_system_id gpio_reset_ids[] = {
{
.ident = "Apple Macbook 10,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
}
},
{ }
};
int
_nouveau_gpio_init(struct nouveau_object *object)
{
struct nouveau_gpio *gpio = nouveau_gpio(object);
int ret;
ret = nouveau_subdev_init(&gpio->base);
if (ret)
return ret;
if (gpio->reset && dmi_check_system(gpio_reset_ids))
gpio->reset(gpio, DCB_GPIO_UNUSED);
return ret;
}
void void
_nouveau_gpio_dtor(struct nouveau_object *object) _nouveau_gpio_dtor(struct nouveau_object *object)
{ {
...@@ -113,9 +190,10 @@ _nouveau_gpio_dtor(struct nouveau_object *object) ...@@ -113,9 +190,10 @@ _nouveau_gpio_dtor(struct nouveau_object *object)
int int
nouveau_gpio_create_(struct nouveau_object *parent, nouveau_gpio_create_(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,
struct nouveau_oclass *oclass, int lines, struct nouveau_oclass *oclass,
int length, void **pobject) int length, void **pobject)
{ {
const struct nouveau_gpio_impl *impl = (void *)oclass;
struct nouveau_gpio *gpio; struct nouveau_gpio *gpio;
int ret; int ret;
...@@ -125,34 +203,34 @@ nouveau_gpio_create_(struct nouveau_object *parent, ...@@ -125,34 +203,34 @@ nouveau_gpio_create_(struct nouveau_object *parent,
if (ret) if (ret)
return ret; return ret;
ret = nouveau_event_create(lines, &gpio->events);
if (ret)
return ret;
gpio->find = nouveau_gpio_find; gpio->find = nouveau_gpio_find;
gpio->set = nouveau_gpio_set; gpio->set = nouveau_gpio_set;
gpio->get = nouveau_gpio_get; gpio->get = nouveau_gpio_get;
gpio->reset = impl->reset;
ret = nouveau_event_create(2, impl->lines, &gpio->events);
if (ret)
return ret;
gpio->events->priv = gpio;
gpio->events->enable = nouveau_gpio_intr_enable;
gpio->events->disable = nouveau_gpio_intr_disable;
nv_subdev(gpio)->intr = nouveau_gpio_intr;
return 0; return 0;
} }
static struct dmi_system_id gpio_reset_ids[] = {
{
.ident = "Apple Macbook 10,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
}
},
{ }
};
int int
nouveau_gpio_init(struct nouveau_gpio *gpio) _nouveau_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{ {
int ret = nouveau_subdev_init(&gpio->base); struct nouveau_gpio *gpio;
if (ret == 0 && gpio->reset) { int ret;
if (dmi_check_system(gpio_reset_ids))
gpio->reset(gpio, DCB_GPIO_UNUSED); ret = nouveau_gpio_create(parent, engine, oclass, &gpio);
} *pobject = nv_object(gpio);
return ret; if (ret)
return ret;
return 0;
} }
...@@ -26,10 +26,6 @@ ...@@ -26,10 +26,6 @@
#include "priv.h" #include "priv.h"
struct nv10_gpio_priv {
struct nouveau_gpio base;
};
static int static int
nv10_gpio_sense(struct nouveau_gpio *gpio, int line) nv10_gpio_sense(struct nouveau_gpio *gpio, int line)
{ {
...@@ -83,95 +79,38 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) ...@@ -83,95 +79,38 @@ nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
} }
static void static void
nv10_gpio_intr(struct nouveau_subdev *subdev) nv10_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
{
struct nv10_gpio_priv *priv = (void *)subdev;
u32 intr = nv_rd32(priv, 0x001104);
u32 hi = (intr & 0x0000ffff) >> 0;
u32 lo = (intr & 0xffff0000) >> 16;
int i;
for (i = 0; (hi | lo) && i < 32; i++) {
if ((hi | lo) & (1 << i))
nouveau_event_trigger(priv->base.events, i);
}
nv_wr32(priv, 0x001104, intr);
}
static void
nv10_gpio_intr_enable(struct nouveau_event *event, int line)
{
nv_wr32(event->priv, 0x001104, 0x00010001 << line);
nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00010001 << line);
}
static void
nv10_gpio_intr_disable(struct nouveau_event *event, int line)
{
nv_wr32(event->priv, 0x001104, 0x00010001 << line);
nv_mask(event->priv, 0x001144, 0x00010001 << line, 0x00000000);
}
static int
nv10_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{ {
struct nv10_gpio_priv *priv; u32 intr = nv_rd32(gpio, 0x001104);
int ret; u32 stat = nv_rd32(gpio, 0x001144) & intr;
*lo = (stat & 0xffff0000) >> 16;
ret = nouveau_gpio_create(parent, engine, oclass, 16, &priv); *hi = (stat & 0x0000ffff);
*pobject = nv_object(priv); nv_wr32(gpio, 0x001104, intr);
if (ret)
return ret;
priv->base.drive = nv10_gpio_drive;
priv->base.sense = nv10_gpio_sense;
priv->base.events->priv = priv;
priv->base.events->enable = nv10_gpio_intr_enable;
priv->base.events->disable = nv10_gpio_intr_disable;
nv_subdev(priv)->intr = nv10_gpio_intr;
return 0;
} }
static void static void
nv10_gpio_dtor(struct nouveau_object *object) nv10_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
{
struct nv10_gpio_priv *priv = (void *)object;
nouveau_gpio_destroy(&priv->base);
}
static int
nv10_gpio_init(struct nouveau_object *object)
{
struct nv10_gpio_priv *priv = (void *)object;
int ret;
ret = nouveau_gpio_init(&priv->base);
if (ret)
return ret;
nv_wr32(priv, 0x001144, 0x00000000);
nv_wr32(priv, 0x001104, 0xffffffff);
return 0;
}
static int
nv10_gpio_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv10_gpio_priv *priv = (void *)object; u32 inte = nv_rd32(gpio, 0x001144);
nv_wr32(priv, 0x001144, 0x00000000); if (type & NVKM_GPIO_LO)
return nouveau_gpio_fini(&priv->base, suspend); inte = (inte & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte = (inte & ~mask) | data;
nv_wr32(gpio, 0x001144, inte);
} }
struct nouveau_oclass struct nouveau_oclass *
nv10_gpio_oclass = { nv10_gpio_oclass = &(struct nouveau_gpio_impl) {
.handle = NV_SUBDEV(GPIO, 0x10), .base.handle = NV_SUBDEV(GPIO, 0x10),
.ofuncs = &(struct nouveau_ofuncs) { .base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv10_gpio_ctor, .ctor = _nouveau_gpio_ctor,
.dtor = nv10_gpio_dtor, .dtor = _nouveau_gpio_dtor,
.init = nv10_gpio_init, .init = _nouveau_gpio_init,
.fini = nv10_gpio_fini, .fini = _nouveau_gpio_fini,
}, },
}; .lines = 16,
.intr_stat = nv10_gpio_intr_stat,
.intr_mask = nv10_gpio_intr_mask,
.drive = nv10_gpio_drive,
.sense = nv10_gpio_sense,
}.base;
...@@ -24,15 +24,10 @@ ...@@ -24,15 +24,10 @@
#include "priv.h" #include "priv.h"
struct nv50_gpio_priv { void
struct nouveau_gpio base;
};
static void
nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
{ {
struct nouveau_bios *bios = nouveau_bios(gpio); struct nouveau_bios *bios = nouveau_bios(gpio);
struct nv50_gpio_priv *priv = (void *)gpio;
u8 ver, len; u8 ver, len;
u16 entry; u16 entry;
int ent = -1; int ent = -1;
...@@ -55,7 +50,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) ...@@ -55,7 +50,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
gpio->set(gpio, 0, func, line, defs); gpio->set(gpio, 0, func, line, defs);
nv_mask(priv, reg, 0x00010001 << lsh, val << lsh); nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh);
} }
} }
...@@ -72,7 +67,7 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift) ...@@ -72,7 +67,7 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift)
return 0; return 0;
} }
static int int
nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
{ {
u32 reg, shift; u32 reg, shift;
...@@ -84,7 +79,7 @@ nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) ...@@ -84,7 +79,7 @@ nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
return 0; return 0;
} }
static int int
nv50_gpio_sense(struct nouveau_gpio *gpio, int line) nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
{ {
u32 reg, shift; u32 reg, shift;
...@@ -95,119 +90,40 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line) ...@@ -95,119 +90,40 @@ nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
return !!(nv_rd32(gpio, reg) & (4 << shift)); return !!(nv_rd32(gpio, reg) & (4 << shift));
} }
void static void
nv50_gpio_intr(struct nouveau_subdev *subdev) nv50_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
{
struct nv50_gpio_priv *priv = (void *)subdev;
u32 intr0, intr1 = 0;
u32 hi, lo;
int i;
intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
if (nv_device(priv)->chipset > 0x92)
intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
hi = (intr0 & 0x0000ffff) | (intr1 << 16);
lo = (intr0 >> 16) | (intr1 & 0xffff0000);
for (i = 0; (hi | lo) && i < 32; i++) {
if ((hi | lo) & (1 << i))
nouveau_event_trigger(priv->base.events, i);
}
nv_wr32(priv, 0xe054, intr0);
if (nv_device(priv)->chipset > 0x92)
nv_wr32(priv, 0xe074, intr1);
}
void
nv50_gpio_intr_enable(struct nouveau_event *event, int line)
{
const u32 addr = line < 16 ? 0xe050 : 0xe070;
const u32 mask = 0x00010001 << (line & 0xf);
nv_wr32(event->priv, addr + 0x04, mask);
nv_mask(event->priv, addr + 0x00, mask, mask);
}
void
nv50_gpio_intr_disable(struct nouveau_event *event, int line)
{
const u32 addr = line < 16 ? 0xe050 : 0xe070;
const u32 mask = 0x00010001 << (line & 0xf);
nv_wr32(event->priv, addr + 0x04, mask);
nv_mask(event->priv, addr + 0x00, mask, 0x00000000);
}
static int
nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nv50_gpio_priv *priv;
int ret;
ret = nouveau_gpio_create(parent, engine, oclass,
nv_device(parent)->chipset > 0x92 ? 32 : 16,
&priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.reset = nv50_gpio_reset;
priv->base.drive = nv50_gpio_drive;
priv->base.sense = nv50_gpio_sense;
priv->base.events->priv = priv;
priv->base.events->enable = nv50_gpio_intr_enable;
priv->base.events->disable = nv50_gpio_intr_disable;
nv_subdev(priv)->intr = nv50_gpio_intr;
return 0;
}
void
nv50_gpio_dtor(struct nouveau_object *object)
{
struct nv50_gpio_priv *priv = (void *)object;
nouveau_gpio_destroy(&priv->base);
}
int
nv50_gpio_init(struct nouveau_object *object)
{ {
struct nv50_gpio_priv *priv = (void *)object; u32 intr = nv_rd32(gpio, 0x00e054);
int ret; u32 stat = nv_rd32(gpio, 0x00e050) & intr;
*lo = (stat & 0xffff0000) >> 16;
ret = nouveau_gpio_init(&priv->base); *hi = (stat & 0x0000ffff);
if (ret) nv_wr32(gpio, 0x00e054, intr);
return ret;
/* disable, and ack any pending gpio interrupts */
nv_wr32(priv, 0xe050, 0x00000000);
nv_wr32(priv, 0xe054, 0xffffffff);
if (nv_device(priv)->chipset > 0x92) {
nv_wr32(priv, 0xe070, 0x00000000);
nv_wr32(priv, 0xe074, 0xffffffff);
}
return 0;
} }
int static void
nv50_gpio_fini(struct nouveau_object *object, bool suspend) nv50_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
{ {
struct nv50_gpio_priv *priv = (void *)object; u32 inte = nv_rd32(gpio, 0x00e050);
nv_wr32(priv, 0xe050, 0x00000000); if (type & NVKM_GPIO_LO)
if (nv_device(priv)->chipset > 0x92) inte = (inte & ~(mask << 16)) | (data << 16);
nv_wr32(priv, 0xe070, 0x00000000); if (type & NVKM_GPIO_HI)
return nouveau_gpio_fini(&priv->base, suspend); inte = (inte & ~mask) | data;
nv_wr32(gpio, 0x00e050, inte);
} }
struct nouveau_oclass struct nouveau_oclass *
nv50_gpio_oclass = { nv50_gpio_oclass = &(struct nouveau_gpio_impl) {
.handle = NV_SUBDEV(GPIO, 0x50), .base.handle = NV_SUBDEV(GPIO, 0x50),
.ofuncs = &(struct nouveau_ofuncs) { .base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_gpio_ctor, .ctor = _nouveau_gpio_ctor,
.dtor = nv50_gpio_dtor, .dtor = _nouveau_gpio_dtor,
.init = nv50_gpio_init, .init = _nouveau_gpio_init,
.fini = nv50_gpio_fini, .fini = _nouveau_gpio_fini,
}, },
}; .lines = 16,
.intr_stat = nv50_gpio_intr_stat,
.intr_mask = nv50_gpio_intr_mask,
.drive = nv50_gpio_drive,
.sense = nv50_gpio_sense,
.reset = nv50_gpio_reset,
}.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 "priv.h"
void
nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
{
u32 intr0 = nv_rd32(gpio, 0x00e054);
u32 intr1 = nv_rd32(gpio, 0x00e074);
u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
nv_wr32(gpio, 0x00e054, intr0);
nv_wr32(gpio, 0x00e074, intr1);
}
void
nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
{
u32 inte0 = nv_rd32(gpio, 0x00e050);
u32 inte1 = nv_rd32(gpio, 0x00e070);
if (type & NVKM_GPIO_LO)
inte0 = (inte0 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
mask >>= 16;
data >>= 16;
if (type & NVKM_GPIO_LO)
inte1 = (inte1 & ~(mask << 16)) | (data << 16);
if (type & NVKM_GPIO_HI)
inte1 = (inte1 & ~mask) | data;
nv_wr32(gpio, 0x00e050, inte0);
nv_wr32(gpio, 0x00e070, inte1);
}
struct nouveau_oclass *
nv92_gpio_oclass = &(struct nouveau_gpio_impl) {
.base.handle = NV_SUBDEV(GPIO, 0x92),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_gpio_ctor,
.dtor = _nouveau_gpio_dtor,
.init = _nouveau_gpio_init,
.fini = _nouveau_gpio_fini,
},
.lines = 32,
.intr_stat = nv92_gpio_intr_stat,
.intr_mask = nv92_gpio_intr_mask,
.drive = nv50_gpio_drive,
.sense = nv50_gpio_sense,
.reset = nv50_gpio_reset,
}.base;
#ifndef __NV50_I2C_H__ #ifndef __NV50_I2C_H__
#define __NV50_I2C_H__ #define __NV50_I2C_H__
#include <subdev/i2c.h> #include "priv.h"
struct nv50_i2c_priv { struct nv50_i2c_priv {
struct nouveau_i2c base; struct nouveau_i2c base;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -34,7 +34,8 @@ nv50_mc_intr[] = { ...@@ -34,7 +34,8 @@ nv50_mc_intr[] = {
{ 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */
{ 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */ { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */
{ 0x00100000, NVDEV_SUBDEV_TIMER }, { 0x00100000, NVDEV_SUBDEV_TIMER },
{ 0x00200000, NVDEV_SUBDEV_GPIO }, { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
{ 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
{ 0x10000000, NVDEV_SUBDEV_BUS }, { 0x10000000, NVDEV_SUBDEV_BUS },
{ 0x80000000, NVDEV_ENGINE_SW }, { 0x80000000, NVDEV_ENGINE_SW },
{ 0x0002d101, NVDEV_SUBDEV_FB }, { 0x0002d101, NVDEV_SUBDEV_FB },
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册