Commit 4ac07364 authored by Dave Airlie's avatar Dave Airlie

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

This is the main merge request for Nouveau 3.18, overview:
- various bits of roy's gt21x clock work
- various bits of kepler memory clock work (don't get too excited, there's at least one more major bit left that's busting higher freqs)
- misc fan control improvements
- kepler hdmi infoframe fixes
- dp audio
- l2 cache + cbc improvements

* 'linux-3.18' of git://anongit.freedesktop.org/git/nouveau/linux-2.6: (68 commits)
  drm/gt214-/disp: enable dp audio
  drm/gt214-/kms: fix hda eld regression
  drm/g94-/disp: calculate some dp audio constants
  drm/gt214-/kms: perform hda codec setup on displayport too
  drm/gk104-/disp: infoframe registers moved yet again on kepler
  drm/nouveau/bios: parse older ramcfg/timing data like we do newer ones
  drm/nva3/fb/ram: Per-partition regs
  drm/nouveau/fb/ram: Support strided regs
  drm/nv50/fb/ram: Store the number of partitions in the designated fields
  drm/nv50/kms: Set VBLANK time in modeset script
  drm/nouveau/bios: Add rammap support for version 1.0
  drm/gf100-/pwr/memx: block host and fifo around reclock
  drm/nouveau/pwr/memx: fix command ordering around block/unblock
  drm/nouveau/pwr/memx: rename fb off/on to block/unblock
  drm/nva3/clk: Pause the GPU before reclocking
  drm/nouveau/gpio: rename g92 class to g94
  drm/gk104-/fb/ram: move fb enable/disable to same place as nvidia
  drm/gk104/fb/ram: twiddle some more bits when reclocking
  drm/nouveau/bios: parse another large chunk of random memory config data
  drm/gk104-/fb/ram: perform certain steps only when bios data differs
  ...
parents 19524f7c cc2a9071
......@@ -38,6 +38,7 @@ nouveau-y += core/subdev/bios/dcb.o
nouveau-y += core/subdev/bios/disp.o
nouveau-y += core/subdev/bios/dp.o
nouveau-y += core/subdev/bios/extdev.o
nouveau-y += core/subdev/bios/fan.o
nouveau-y += core/subdev/bios/gpio.o
nouveau-y += core/subdev/bios/i2c.o
nouveau-y += core/subdev/bios/init.o
......@@ -51,6 +52,8 @@ nouveau-y += core/subdev/bios/therm.o
nouveau-y += core/subdev/bios/vmap.o
nouveau-y += core/subdev/bios/volt.o
nouveau-y += core/subdev/bios/xpio.o
nouveau-y += core/subdev/bios/M0205.o
nouveau-y += core/subdev/bios/M0209.o
nouveau-y += core/subdev/bios/P0260.o
nouveau-y += core/subdev/bus/hwsq.o
nouveau-y += core/subdev/bus/nv04.o
......@@ -124,12 +127,17 @@ nouveau-y += core/subdev/fb/ramnvc0.o
nouveau-y += core/subdev/fb/ramnve0.o
nouveau-y += core/subdev/fb/ramgk20a.o
nouveau-y += core/subdev/fb/ramgm107.o
nouveau-y += core/subdev/fb/sddr2.o
nouveau-y += core/subdev/fb/sddr3.o
nouveau-y += core/subdev/fb/gddr5.o
nouveau-y += core/subdev/fuse/base.o
nouveau-y += core/subdev/fuse/g80.o
nouveau-y += core/subdev/fuse/gf100.o
nouveau-y += core/subdev/fuse/gm107.o
nouveau-y += core/subdev/gpio/base.o
nouveau-y += core/subdev/gpio/nv10.o
nouveau-y += core/subdev/gpio/nv50.o
nouveau-y += core/subdev/gpio/nv92.o
nouveau-y += core/subdev/gpio/nv94.o
nouveau-y += core/subdev/gpio/nvd0.o
nouveau-y += core/subdev/gpio/nve0.o
nouveau-y += core/subdev/i2c/base.o
......@@ -190,6 +198,7 @@ nouveau-y += core/subdev/therm/nv50.o
nouveau-y += core/subdev/therm/nv84.o
nouveau-y += core/subdev/therm/nva3.o
nouveau-y += core/subdev/therm/nvd0.o
nouveau-y += core/subdev/therm/gm107.o
nouveau-y += core/subdev/timer/base.o
nouveau-y += core/subdev/timer/nv04.o
nouveau-y += core/subdev/timer/gk20a.o
......@@ -252,6 +261,7 @@ nouveau-y += core/engine/disp/hdanvd0.o
nouveau-y += core/engine/disp/hdminv84.o
nouveau-y += core/engine/disp/hdminva3.o
nouveau-y += core/engine/disp/hdminvd0.o
nouveau-y += core/engine/disp/hdminve0.o
nouveau-y += core/engine/disp/piornv50.o
nouveau-y += core/engine/disp/sornv50.o
nouveau-y += core/engine/disp/sornv94.o
......
......@@ -91,9 +91,10 @@ nvkm_client_notify_del(struct nouveau_client *client, int index)
}
int
nvkm_client_notify_new(struct nouveau_client *client,
nvkm_client_notify_new(struct nouveau_object *object,
struct nvkm_event *event, void *data, u32 size)
{
struct nouveau_client *client = nouveau_client(object);
struct nvkm_client_notify *notify;
union {
struct nvif_notify_req_v0 v0;
......@@ -127,8 +128,8 @@ nvkm_client_notify_new(struct nouveau_client *client,
}
if (ret == 0) {
ret = nvkm_notify_init(event, nvkm_client_notify, false,
data, size, reply, &notify->n);
ret = nvkm_notify_init(object, event, nvkm_client_notify,
false, data, size, reply, &notify->n);
if (ret == 0) {
client->notify[index] = notify;
notify->client = client;
......
......@@ -20,7 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <core/os.h>
#include <core/object.h>
#include <core/event.h>
void
......
......@@ -115,7 +115,7 @@ nouveau_gpuobj_create_(struct nouveau_object *parent,
gpuobj->size = size;
if (heap) {
ret = nouveau_mm_head(heap, 1, size, size,
ret = nouveau_mm_head(heap, 0, 1, size, size,
max(align, (u32)1), &gpuobj->node);
if (ret)
return ret;
......
......@@ -349,7 +349,6 @@ nvkm_ioctl_unmap(struct nouveau_handle *handle, void *data, u32 size)
static int
nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
{
struct nouveau_client *client = nouveau_client(handle->object);
struct nouveau_object *object = handle->object;
struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
union {
......@@ -365,7 +364,7 @@ nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
if (ret = -ENODEV, ofuncs->ntfy)
ret = ofuncs->ntfy(object, args->v0.event, &event);
if (ret == 0) {
ret = nvkm_client_notify_new(client, event, data, size);
ret = nvkm_client_notify_new(object, event, data, size);
if (ret >= 0) {
args->v0.index = ret;
ret = 0;
......
......@@ -28,6 +28,24 @@
#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
static void
nouveau_mm_dump(struct nouveau_mm *mm, const char *header)
{
struct nouveau_mm_node *node;
printk(KERN_ERR "nouveau: %s\n", header);
printk(KERN_ERR "nouveau: node list:\n");
list_for_each_entry(node, &mm->nodes, nl_entry) {
printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
node->offset, node->length, node->type);
}
printk(KERN_ERR "nouveau: free list:\n");
list_for_each_entry(node, &mm->free, fl_entry) {
printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
node->offset, node->length, node->type);
}
}
void
nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
{
......@@ -37,29 +55,29 @@ nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
struct nouveau_mm_node *prev = node(this, prev);
struct nouveau_mm_node *next = node(this, next);
if (prev && prev->type == 0) {
if (prev && prev->type == NVKM_MM_TYPE_NONE) {
prev->length += this->length;
list_del(&this->nl_entry);
kfree(this); this = prev;
}
if (next && next->type == 0) {
if (next && next->type == NVKM_MM_TYPE_NONE) {
next->offset = this->offset;
next->length += this->length;
if (this->type == 0)
if (this->type == NVKM_MM_TYPE_NONE)
list_del(&this->fl_entry);
list_del(&this->nl_entry);
kfree(this); this = NULL;
}
if (this && this->type != 0) {
if (this && this->type != NVKM_MM_TYPE_NONE) {
list_for_each_entry(prev, &mm->free, fl_entry) {
if (this->offset < prev->offset)
break;
}
list_add_tail(&this->fl_entry, &prev->fl_entry);
this->type = 0;
this->type = NVKM_MM_TYPE_NONE;
}
}
......@@ -80,27 +98,32 @@ region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
b->offset = a->offset;
b->length = size;
b->heap = a->heap;
b->type = a->type;
a->offset += size;
a->length -= size;
list_add_tail(&b->nl_entry, &a->nl_entry);
if (b->type == 0)
if (b->type == NVKM_MM_TYPE_NONE)
list_add_tail(&b->fl_entry, &a->fl_entry);
return b;
}
int
nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
u32 align, struct nouveau_mm_node **pnode)
nouveau_mm_head(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
u32 size_min, u32 align, struct nouveau_mm_node **pnode)
{
struct nouveau_mm_node *prev, *this, *next;
u32 mask = align - 1;
u32 splitoff;
u32 s, e;
BUG_ON(!type);
BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
list_for_each_entry(this, &mm->free, fl_entry) {
if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
if (this->heap != heap)
continue;
}
e = this->offset + this->length;
s = this->offset;
......@@ -149,27 +172,32 @@ region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
a->length -= size;
b->offset = a->offset + a->length;
b->length = size;
b->heap = a->heap;
b->type = a->type;
list_add(&b->nl_entry, &a->nl_entry);
if (b->type == 0)
if (b->type == NVKM_MM_TYPE_NONE)
list_add(&b->fl_entry, &a->fl_entry);
return b;
}
int
nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
u32 align, struct nouveau_mm_node **pnode)
nouveau_mm_tail(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
u32 size_min, u32 align, struct nouveau_mm_node **pnode)
{
struct nouveau_mm_node *prev, *this, *next;
u32 mask = align - 1;
BUG_ON(!type);
BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
list_for_each_entry_reverse(this, &mm->free, fl_entry) {
u32 e = this->offset + this->length;
u32 s = this->offset;
u32 c = 0, a;
if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
if (this->heap != heap)
continue;
}
prev = node(this, prev);
if (prev && prev->type != type)
......@@ -209,9 +237,23 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min,
int
nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
{
struct nouveau_mm_node *node;
struct nouveau_mm_node *node, *prev;
u32 next;
if (block) {
if (nouveau_mm_initialised(mm)) {
prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
next = prev->offset + prev->length;
if (next != offset) {
BUG_ON(next > offset);
if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
return -ENOMEM;
node->type = NVKM_MM_TYPE_HOLE;
node->offset = next;
node->length = offset - next;
list_add_tail(&node->nl_entry, &mm->nodes);
}
BUG_ON(block != mm->block_size);
} else {
INIT_LIST_HEAD(&mm->nodes);
INIT_LIST_HEAD(&mm->free);
mm->block_size = block;
......@@ -230,25 +272,32 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
list_add_tail(&node->nl_entry, &mm->nodes);
list_add_tail(&node->fl_entry, &mm->free);
mm->heap_nodes++;
node->heap = ++mm->heap_nodes;
return 0;
}
int
nouveau_mm_fini(struct nouveau_mm *mm)
{
if (nouveau_mm_initialised(mm)) {
struct nouveau_mm_node *node, *heap =
list_first_entry(&mm->nodes, typeof(*heap), nl_entry);
struct nouveau_mm_node *node, *temp;
int nodes = 0;
if (!nouveau_mm_initialised(mm))
return 0;
list_for_each_entry(node, &mm->nodes, nl_entry) {
if (WARN_ON(nodes++ == mm->heap_nodes))
if (node->type != NVKM_MM_TYPE_HOLE) {
if (++nodes > mm->heap_nodes) {
nouveau_mm_dump(mm, "mm not clean!");
return -EBUSY;
}
kfree(heap);
}
}
list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
list_del(&node->nl_entry);
kfree(node);
}
mm->heap_nodes = 0;
return 0;
}
......@@ -134,14 +134,15 @@ nvkm_notify_fini(struct nvkm_notify *notify)
}
int
nvkm_notify_init(struct nvkm_event *event, int (*func)(struct nvkm_notify *),
bool work, void *data, u32 size, u32 reply,
nvkm_notify_init(struct nouveau_object *object, struct nvkm_event *event,
int (*func)(struct nvkm_notify *), bool work,
void *data, u32 size, u32 reply,
struct nvkm_notify *notify)
{
unsigned long flags;
int ret = -ENODEV;
if ((notify->event = event), event->refs) {
ret = event->func->ctor(data, size, notify);
ret = event->func->ctor(object, data, size, notify);
if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
notify->flags = 0;
notify->block = 1;
......
......@@ -505,7 +505,8 @@ nouveau_device_sclass[] = {
};
static int
nouveau_device_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
nouveau_device_event_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
if (!WARN_ON(size != 0)) {
notify->size = 0;
......
......@@ -26,6 +26,7 @@
#include <subdev/bus.h>
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/fuse.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/mxm.h>
......@@ -62,10 +63,9 @@ gm100_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
#if 0
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
#endif
device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
......@@ -77,8 +77,9 @@ gm100_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
#if 0
device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
#if 0
device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
#endif
device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
......
......@@ -26,6 +26,7 @@
#include <subdev/bus.h>
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/fuse.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/mxm.h>
......@@ -62,6 +63,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -87,6 +89,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -115,6 +118,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -141,8 +145,9 @@ nv50_identify(struct nouveau_device *device)
case 0x92:
device->cname = "G92";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -169,8 +174,9 @@ nv50_identify(struct nouveau_device *device)
case 0x94:
device->cname = "G94";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -197,8 +203,9 @@ nv50_identify(struct nouveau_device *device)
case 0x96:
device->cname = "G96";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -225,8 +232,9 @@ nv50_identify(struct nouveau_device *device)
case 0x98:
device->cname = "G98";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -253,8 +261,9 @@ nv50_identify(struct nouveau_device *device)
case 0xa0:
device->cname = "G200";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -281,8 +290,9 @@ nv50_identify(struct nouveau_device *device)
case 0xaa:
device->cname = "MCP77/MCP78";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -309,8 +319,9 @@ nv50_identify(struct nouveau_device *device)
case 0xac:
device->cname = "MCP79/MCP7A";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -337,8 +348,9 @@ nv50_identify(struct nouveau_device *device)
case 0xa3:
device->cname = "GT215";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -367,8 +379,9 @@ nv50_identify(struct nouveau_device *device)
case 0xa5:
device->cname = "GT216";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -396,8 +409,9 @@ nv50_identify(struct nouveau_device *device)
case 0xa8:
device->cname = "GT218";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -425,8 +439,9 @@ nv50_identify(struct nouveau_device *device)
case 0xaf:
device->cname = "MCP89";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
......@@ -26,6 +26,7 @@
#include <subdev/bus.h>
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/fuse.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/mxm.h>
......@@ -60,8 +61,9 @@ nvc0_identify(struct nouveau_device *device)
case 0xc0:
device->cname = "GF100";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -92,8 +94,9 @@ nvc0_identify(struct nouveau_device *device)
case 0xc4:
device->cname = "GF104";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -124,8 +127,9 @@ nvc0_identify(struct nouveau_device *device)
case 0xc3:
device->cname = "GF106";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -155,8 +159,9 @@ nvc0_identify(struct nouveau_device *device)
case 0xce:
device->cname = "GF114";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -187,8 +192,9 @@ nvc0_identify(struct nouveau_device *device)
case 0xcf:
device->cname = "GF116";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -219,8 +225,9 @@ nvc0_identify(struct nouveau_device *device)
case 0xc1:
device->cname = "GF108";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -250,8 +257,9 @@ nvc0_identify(struct nouveau_device *device)
case 0xc8:
device->cname = "GF110";
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv92_gpio_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -284,6 +292,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -315,6 +324,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
......@@ -26,6 +26,7 @@
#include <subdev/bus.h>
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/fuse.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/mxm.h>
......@@ -62,6 +63,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -95,6 +97,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -128,6 +131,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -161,6 +165,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &gk20a_clock_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass;
device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
......@@ -180,6 +185,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -213,6 +219,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......@@ -246,6 +253,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
......
......@@ -32,7 +32,8 @@
#include "conn.h"
int
nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *notify)
nouveau_disp_vblank_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nouveau_disp *disp =
container_of(notify->event, typeof(*disp), vblank);
......@@ -61,7 +62,8 @@ nouveau_disp_vblank(struct nouveau_disp *disp, int head)
}
static int
nouveau_disp_hpd_ctor(void *data, u32 size, struct nvkm_notify *notify)
nouveau_disp_hpd_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nouveau_disp *disp =
container_of(notify->event, typeof(*disp), hpd);
......
......@@ -126,8 +126,8 @@ nvkm_connector_create_(struct nouveau_object *parent,
return 0;
}
ret = nvkm_notify_init(&gpio->event, nvkm_connector_hpd, true,
&(struct nvkm_gpio_ntfy_req) {
ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
true, &(struct nvkm_gpio_ntfy_req) {
.mask = NVKM_GPIO_TOGGLED,
.line = func.line,
},
......
......@@ -68,6 +68,10 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = gm107_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
......@@ -80,7 +84,7 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.hdmi = nve0_hdmi_ctrl;
return 0;
}
......
......@@ -26,6 +26,8 @@
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/timer.h>
#include "nv50.h"
int
......@@ -46,16 +48,21 @@ nva3_hda_eld(NV50_DISP_MTHD_V1)
return ret;
if (size && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
}
for (i = 0; i < size; i++)
nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
for (; i < 0x60; i++)
nv_wr32(priv, 0x61c440 + soff, (i << 8));
nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
} else
if (size) {
nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000001);
} else {
nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000);
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000);
nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
}
nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
}
return 0;
......
......@@ -26,10 +26,7 @@
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/dp.h>
#include <subdev/bios/init.h>
#include <subdev/timer.h>
#include "nv50.h"
......@@ -40,6 +37,7 @@ nvd0_hda_eld(NV50_DISP_MTHD_V1)
struct nv50_disp_sor_hda_eld_v0 v0;
} *args = data;
const u32 soff = outp->or * 0x030;
const u32 hoff = head * 0x800;
int ret, i;
nv_ioctl(object, "disp sor hda eld size %d\n", size);
......@@ -51,16 +49,22 @@ nvd0_hda_eld(NV50_DISP_MTHD_V1)
return ret;
if (size && args->v0.data[0]) {
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001);
nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
}
nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
for (i = 0; i < size; i++)
nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
for (; i < 0x60; i++)
nv_wr32(priv, 0x10ec00 + soff, (i << 8));
nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
} else
if (size) {
nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000001);
} else {
nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000);
if (outp->info.type == DCB_OUTPUT_DP) {
nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000);
nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
}
nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
}
return 0;
......
......@@ -75,8 +75,5 @@ nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1)
/* HDMI_CTRL */
nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
/* NFI, audio doesn't work without it though.. */
nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
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 <core/client.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include "nv50.h"
int
nve0_hdmi_ctrl(NV50_DISP_MTHD_V1)
{
const u32 hoff = (head * 0x800);
const u32 hdmi = (head * 0x400);
union {
struct nv50_disp_sor_hdmi_pwr_v0 v0;
} *args = data;
u32 ctrl;
int ret;
nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
if (nvif_unpack(args->v0, 0, 0, false)) {
nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
"max_ac_packet %d rekey %d\n",
args->v0.version, args->v0.state,
args->v0.max_ac_packet, args->v0.rekey);
if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
return -EINVAL;
ctrl = 0x40000000 * !!args->v0.state;
ctrl |= args->v0.max_ac_packet << 16;
ctrl |= args->v0.rekey;
} else
return ret;
if (!(ctrl & 0x40000000)) {
nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
return 0;
}
/* AVI InfoFrame */
nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
nv_wr32(priv, 0x690008 + hdmi, 0x000d0282);
nv_wr32(priv, 0x69000c + hdmi, 0x0000006f);
nv_wr32(priv, 0x690010 + hdmi, 0x00000000);
nv_wr32(priv, 0x690014 + hdmi, 0x00000000);
nv_wr32(priv, 0x690018 + hdmi, 0x00000000);
nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001);
/* ??? InfoFrame? */
nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
nv_wr32(priv, 0x6900cc + hdmi, 0x00000010);
nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
/* ??? */
nv_wr32(priv, 0x690080 + hdmi, 0x82000000);
/* HDMI_CTRL */
nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
return 0;
}
......@@ -29,6 +29,7 @@
#include <core/enum.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <nvif/event.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
......@@ -82,6 +83,71 @@ nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
nouveau_namedb_destroy(&chan->base);
}
static void
nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
}
static void
nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
}
void
nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid)
{
struct nvif_notify_uevent_rep {
} rep;
nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep));
}
int
nv50_disp_chan_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nv50_disp_dmac *dmac = (void *)object;
union {
struct nvif_notify_uevent_req none;
} *args = data;
int ret;
if (nvif_unvers(args->none)) {
notify->size = sizeof(struct nvif_notify_uevent_rep);
notify->types = 1;
notify->index = dmac->base.chid;
return 0;
}
return ret;
}
const struct nvkm_event_func
nv50_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
.init = nv50_disp_chan_uevent_init,
.fini = nv50_disp_chan_uevent_fini,
};
int
nv50_disp_chan_ntfy(struct nouveau_object *object, u32 type,
struct nvkm_event **pevent)
{
struct nv50_disp_priv *priv = (void *)object->engine;
switch (type) {
case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
*pevent = &priv->uevent;
return 0;
default:
break;
}
return -EINVAL;
}
int
nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size)
{
......@@ -195,7 +261,7 @@ nv50_disp_dmac_init(struct nouveau_object *object)
return ret;
/* enable error reporting */
nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid);
/* initialise channel for dma command submission */
nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
......@@ -232,7 +298,7 @@ nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
return -EBUSY;
}
/* disable error reporting */
/* disable error reporting and completion notifications */
nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
return nv50_disp_chan_fini(&dmac->base, suspend);
......@@ -454,7 +520,7 @@ nv50_disp_mast_init(struct nouveau_object *object)
return ret;
/* enable error reporting */
nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
nv_mask(priv, 0x610028, 0x00010000, 0x00010000);
/* attempt to unstick channel from some unknown state */
if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
......@@ -494,7 +560,7 @@ nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
return -EBUSY;
}
/* disable error reporting */
/* disable error reporting and completion notifications */
nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
return nv50_disp_chan_fini(&mast->base, suspend);
......@@ -507,6 +573,7 @@ nv50_disp_mast_ofuncs = {
.base.init = nv50_disp_mast_init,
.base.fini = nv50_disp_mast_fini,
.base.map = nv50_disp_chan_map,
.base.ntfy = nv50_disp_chan_ntfy,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
.chid = 0,
......@@ -607,6 +674,7 @@ nv50_disp_sync_ofuncs = {
.base.dtor = nv50_disp_dmac_dtor,
.base.init = nv50_disp_dmac_init,
.base.fini = nv50_disp_dmac_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -696,6 +764,7 @@ nv50_disp_ovly_ofuncs = {
.base.dtor = nv50_disp_dmac_dtor,
.base.init = nv50_disp_dmac_init,
.base.fini = nv50_disp_dmac_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -813,6 +882,7 @@ nv50_disp_oimm_ofuncs = {
.base.dtor = nv50_disp_pioc_dtor,
.base.init = nv50_disp_pioc_init,
.base.fini = nv50_disp_pioc_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -860,6 +930,7 @@ nv50_disp_curs_ofuncs = {
.base.dtor = nv50_disp_pioc_dtor,
.base.init = nv50_disp_pioc_init,
.base.fini = nv50_disp_pioc_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -1559,7 +1630,7 @@ nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
}
static void
nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head,
struct dcb_output *outp, u32 pclk)
{
const int link = !(outp->sorconf.link & 1);
......@@ -1568,24 +1639,36 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv,
const u32 loff = (link * 0x080) + soff;
const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
const u32 symbol = 100000;
u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x0000f0000;
const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff;
const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff;
const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff;
u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
u32 clksor = nv_rd32(priv, 0x614300 + soff);
int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
int TU, VTUi, VTUf, VTUa;
u64 link_data_rate, link_ratio, unk;
u32 best_diff = 64 * symbol;
u32 link_nr, link_bw, bits;
/* calculate packed data rate for each lane */
if (dpctrl > 0x00030000) link_nr = 4;
else if (dpctrl > 0x00010000) link_nr = 2;
else link_nr = 1;
if (clksor & 0x000c0000)
link_bw = 270000;
else
link_bw = 162000;
u64 value;
link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
link_nr = hweight32(dpctrl & 0x000f0000);
/* symbols/hblank - algorithm taken from comments in tegra driver */
value = vblanke + vactive - vblanks - 7;
value = value * link_bw;
do_div(value, pclk);
value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value);
/* symbols/vblank - algorithm taken from comments in tegra driver */
value = vblanks - vblanke - 25;
value = value * link_bw;
do_div(value, pclk);
value = value - ((36 / link_nr) + 3) - 1;
nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value);
/* watermark / activesym */
if ((ctrl & 0xf0000) == 0x60000) bits = 30;
else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
else bits = 18;
......@@ -1731,7 +1814,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
} else
if (!outp->info.location) {
if (outp->info.type == DCB_OUTPUT_DP)
nv50_disp_intr_unk20_2_dp(priv, &outp->info, pclk);
nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk);
oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
hval = 0x00000000;
......@@ -1846,6 +1929,12 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
intr0 &= ~(0x00010000 << chid);
}
while (intr0 & 0x0000001f) {
u32 chid = __ffs(intr0 & 0x0000001f);
nv50_disp_chan_uevent_send(priv, chid);
intr0 &= ~(0x00000001 << chid);
}
if (intr1 & 0x00000004) {
nouveau_disp_vblank(&priv->base, 0);
nv_wr32(priv, 0x610024, 0x00000004);
......@@ -1880,6 +1969,10 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nv50_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
......
......@@ -26,6 +26,8 @@ struct nv50_disp_priv {
struct work_struct supervisor;
u32 super;
struct nvkm_event uevent;
struct {
int nr;
} head;
......@@ -75,6 +77,7 @@ int nvd0_hda_eld(NV50_DISP_MTHD_V1);
int nv84_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nva3_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nve0_hdmi_ctrl(NV50_DISP_MTHD_V1);
int nv50_sor_power(NV50_DISP_MTHD_V1);
......@@ -116,9 +119,16 @@ struct nv50_disp_chan {
int chid;
};
int nv50_disp_chan_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
int nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *);
u32 nv50_disp_chan_rd32(struct nouveau_object *, u64);
void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
extern const struct nvkm_event_func nv50_disp_chan_uevent;
int nv50_disp_chan_uevent_ctor(struct nouveau_object *, void *, u32,
struct nvkm_notify *);
void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);
extern const struct nvkm_event_func nvd0_disp_chan_uevent;
#define nv50_disp_chan_init(a) \
nouveau_namedb_init(&(a)->base)
......
......@@ -236,6 +236,10 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nv84_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
......
......@@ -95,6 +95,10 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nv94_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
......
......@@ -112,6 +112,10 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nva0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
......
......@@ -67,6 +67,10 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nva3_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nv50_disp_intr;
......
......@@ -42,6 +42,31 @@
#include "nv50.h"
/*******************************************************************************
* EVO channel base class
******************************************************************************/
static void
nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
}
static void
nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{
struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
}
const struct nvkm_event_func
nvd0_disp_chan_uevent = {
.ctor = nv50_disp_chan_uevent_ctor,
.init = nvd0_disp_chan_uevent_init,
.fini = nvd0_disp_chan_uevent_fini,
};
/*******************************************************************************
* EVO DMA channel base class
******************************************************************************/
......@@ -77,7 +102,6 @@ nvd0_disp_dmac_init(struct nouveau_object *object)
return ret;
/* enable error reporting */
nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
/* initialise channel for dma command submission */
......@@ -115,7 +139,7 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
return -EBUSY;
}
/* disable error reporting */
/* disable error reporting and completion notification */
nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
......@@ -278,7 +302,6 @@ nvd0_disp_mast_init(struct nouveau_object *object)
return ret;
/* enable error reporting */
nv_mask(priv, 0x610090, 0x00000001, 0x00000001);
nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
/* initialise channel for dma command submission */
......@@ -313,7 +336,7 @@ nvd0_disp_mast_fini(struct nouveau_object *object, bool suspend)
return -EBUSY;
}
/* disable error reporting */
/* disable error reporting and completion notification */
nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
......@@ -326,6 +349,7 @@ nvd0_disp_mast_ofuncs = {
.base.dtor = nv50_disp_dmac_dtor,
.base.init = nvd0_disp_mast_init,
.base.fini = nvd0_disp_mast_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -419,6 +443,7 @@ nvd0_disp_sync_ofuncs = {
.base.dtor = nv50_disp_dmac_dtor,
.base.init = nvd0_disp_dmac_init,
.base.fini = nvd0_disp_dmac_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -499,6 +524,7 @@ nvd0_disp_ovly_ofuncs = {
.base.dtor = nv50_disp_dmac_dtor,
.base.init = nvd0_disp_dmac_init,
.base.fini = nvd0_disp_dmac_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -524,7 +550,6 @@ nvd0_disp_pioc_init(struct nouveau_object *object)
return ret;
/* enable error reporting */
nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000001 << chid);
nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
/* activate channel */
......@@ -553,7 +578,7 @@ nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend)
return -EBUSY;
}
/* disable error reporting */
/* disable error reporting and completion notification */
nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
......@@ -570,6 +595,7 @@ nvd0_disp_oimm_ofuncs = {
.base.dtor = nv50_disp_pioc_dtor,
.base.init = nvd0_disp_pioc_init,
.base.fini = nvd0_disp_pioc_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -586,6 +612,7 @@ nvd0_disp_curs_ofuncs = {
.base.dtor = nv50_disp_pioc_dtor,
.base.init = nvd0_disp_pioc_init,
.base.fini = nvd0_disp_pioc_fini,
.base.ntfy = nv50_disp_chan_ntfy,
.base.map = nv50_disp_chan_map,
.base.rd32 = nv50_disp_chan_rd32,
.base.wr32 = nv50_disp_chan_wr32,
......@@ -949,6 +976,9 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
const int or = ffs(outp->or) - 1;
const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020));
const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff;
const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff;
const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff;
const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
const u32 hoff = (head * 0x800);
......@@ -956,23 +986,35 @@ nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
const u32 loff = (link * 0x080) + soff;
const u32 symbol = 100000;
const u32 TU = 64;
u32 dpctrl = nv_rd32(priv, 0x61c10c + loff) & 0x000f0000;
u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
u32 clksor = nv_rd32(priv, 0x612300 + soff);
u32 datarate, link_nr, link_bw, bits;
u64 ratio, value;
link_nr = hweight32(dpctrl & 0x000f0000);
link_bw = (clksor & 0x007c0000) >> 18;
link_bw *= 27000;
/* symbols/hblank - algorithm taken from comments in tegra driver */
value = vblanke + vactive - vblanks - 7;
value = value * link_bw;
do_div(value, pclk);
value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value);
/* symbols/vblank - algorithm taken from comments in tegra driver */
value = vblanks - vblanke - 25;
value = value * link_bw;
do_div(value, pclk);
value = value - ((36 / link_nr) + 3) - 1;
nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value);
/* watermark */
if ((conf & 0x3c0) == 0x180) bits = 30;
else if ((conf & 0x3c0) == 0x140) bits = 24;
else bits = 18;
datarate = (pclk * bits) / 8;
if (dpctrl > 0x00030000) link_nr = 4;
else if (dpctrl > 0x00010000) link_nr = 2;
else link_nr = 1;
link_bw = (clksor & 0x007c0000) >> 18;
link_bw *= 27000;
ratio = datarate;
ratio *= symbol;
do_div(ratio, link_nr * link_bw);
......@@ -1153,7 +1195,11 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
if (intr & 0x00000001) {
u32 stat = nv_rd32(priv, 0x61008c);
nv_wr32(priv, 0x61008c, stat);
while (stat) {
int chid = __ffs(stat); stat &= ~(1 << chid);
nv50_disp_chan_uevent_send(priv, chid);
nv_wr32(priv, 0x61008c, 1 << chid);
}
intr &= ~0x00000001;
}
......@@ -1209,6 +1255,10 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nvd0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
......
......@@ -233,6 +233,10 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nve0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
......@@ -245,7 +249,7 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.hdmi = nve0_hdmi_ctrl;
return 0;
}
......
......@@ -68,6 +68,10 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
if (ret)
return ret;
nv_engine(priv)->sclass = nvf0_disp_base_oclass;
nv_engine(priv)->cclass = &nv50_disp_cclass;
nv_subdev(priv)->intr = nvd0_disp_intr;
......@@ -80,7 +84,7 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->dac.sense = nv50_dac_sense;
priv->sor.power = nv50_sor_power;
priv->sor.hda_eld = nvd0_hda_eld;
priv->sor.hdmi = nvd0_hdmi_ctrl;
priv->sor.hdmi = nve0_hdmi_ctrl;
return 0;
}
......
......@@ -254,7 +254,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
atomic_set(&outp->lt.done, 0);
/* link maintenance */
ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_irq, true,
ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
&(struct nvkm_i2c_ntfy_req) {
.mask = NVKM_I2C_IRQ,
.port = outp->base.edid->index,
......@@ -268,7 +268,7 @@ nvkm_output_dp_create_(struct nouveau_object *parent,
}
/* hotplug detect, replaces gpio-based mechanism with aux events */
ret = nvkm_notify_init(&i2c->event, nvkm_output_dp_hpd, true,
ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
&(struct nvkm_i2c_ntfy_req) {
.mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
.port = outp->base.edid->index,
......
......@@ -40,7 +40,8 @@ int _nouveau_disp_fini(struct nouveau_object *, bool);
extern struct nouveau_oclass *nvkm_output_oclass;
extern struct nouveau_oclass *nvkm_connector_oclass;
int nouveau_disp_vblank_ctor(void *data, u32 size, struct nvkm_notify *);
int nouveau_disp_vblank_ctor(struct nouveau_object *, void *data, u32 size,
struct nvkm_notify *);
void nouveau_disp_vblank(struct nouveau_disp *, int head);
int nouveau_disp_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
......
......@@ -34,7 +34,8 @@
#include <engine/fifo.h>
static int
nouveau_fifo_event_ctor(void *data, u32 size, struct nvkm_notify *notify)
nouveau_fifo_event_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
if (size == 0) {
notify->size = 0;
......@@ -170,7 +171,8 @@ _nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data)
}
int
nouveau_fifo_uevent_ctor(void *data, u32 size, struct nvkm_notify *notify)
nouveau_fifo_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
union {
struct nvif_notify_uevent_req none;
......
......@@ -175,7 +175,8 @@ nv50_software_context_ctor(struct nouveau_object *parent,
return ret;
for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
ret = nvkm_notify_init(&pdisp->vblank, pclass->vblank, false,
ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank,
false,
&(struct nvif_notify_head_req_v0) {
.head = i,
},
......
......@@ -48,7 +48,7 @@ int nouveau_client_init(struct nouveau_client *);
int nouveau_client_fini(struct nouveau_client *, bool suspend);
const char *nouveau_client_name(void *obj);
int nvkm_client_notify_new(struct nouveau_client *, struct nvkm_event *,
int nvkm_client_notify_new(struct nouveau_object *, struct nvkm_event *,
void *data, u32 size);
int nvkm_client_notify_del(struct nouveau_client *, int index);
int nvkm_client_notify_get(struct nouveau_client *, int index);
......
......@@ -24,6 +24,7 @@ enum nv_subdev_type {
* been created, and are allowed to assume any subdevs in the
* list above them exist and have been initialised.
*/
NVDEV_SUBDEV_FUSE,
NVDEV_SUBDEV_MXM,
NVDEV_SUBDEV_MC,
NVDEV_SUBDEV_BUS,
......
......@@ -4,7 +4,8 @@
#include <core/notify.h>
struct nvkm_event_func {
int (*ctor)(void *data, u32 size, struct nvkm_notify *);
int (*ctor)(struct nouveau_object *, void *data, u32 size,
struct nvkm_notify *);
void (*send)(void *data, u32 size, struct nvkm_notify *);
void (*init)(struct nvkm_event *, int type, int index);
void (*fini)(struct nvkm_event *, int type, int index);
......
......@@ -6,6 +6,10 @@ struct nouveau_mm_node {
struct list_head fl_entry;
struct list_head rl_entry;
#define NVKM_MM_HEAP_ANY 0x00
u8 heap;
#define NVKM_MM_TYPE_NONE 0x00
#define NVKM_MM_TYPE_HOLE 0xff
u8 type;
u32 offset;
u32 length;
......@@ -27,10 +31,10 @@ nouveau_mm_initialised(struct nouveau_mm *mm)
int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
int nouveau_mm_fini(struct nouveau_mm *);
int nouveau_mm_head(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min,
u32 align, struct nouveau_mm_node **);
int nouveau_mm_tail(struct nouveau_mm *, u8 type, u32 size_max, u32 size_min,
u32 align, struct nouveau_mm_node **);
int nouveau_mm_head(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
u32 size_min, u32 align, struct nouveau_mm_node **);
int nouveau_mm_tail(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
u32 size_min, u32 align, struct nouveau_mm_node **);
void nouveau_mm_free(struct nouveau_mm *, struct nouveau_mm_node **);
#endif
......@@ -25,8 +25,9 @@ struct nvkm_notify {
const void *data;
};
int nvkm_notify_init(struct nvkm_event *, int (*func)(struct nvkm_notify *),
bool work, void *data, u32 size, u32 reply,
int nvkm_notify_init(struct nouveau_object *, struct nvkm_event *,
int (*func)(struct nvkm_notify *), bool work,
void *data, u32 size, u32 reply,
struct nvkm_notify *);
void nvkm_notify_fini(struct nvkm_notify *);
void nvkm_notify_get(struct nvkm_notify *);
......
......@@ -116,7 +116,8 @@ extern struct nouveau_oclass *nve0_fifo_oclass;
extern struct nouveau_oclass *gk20a_fifo_oclass;
extern struct nouveau_oclass *nv108_fifo_oclass;
int nouveau_fifo_uevent_ctor(void *, u32, struct nvkm_notify *);
int nouveau_fifo_uevent_ctor(struct nouveau_object *, void *, u32,
struct nvkm_notify *);
void nouveau_fifo_uevent(struct nouveau_fifo *);
void nv04_fifo_intr(struct nouveau_subdev *);
......
......@@ -12,7 +12,6 @@ struct nouveau_bar {
int (*alloc)(struct nouveau_bar *, struct nouveau_object *,
struct nouveau_mem *, struct nouveau_object **);
void __iomem *iomem;
int (*kmap)(struct nouveau_bar *, struct nouveau_mem *,
u32 flags, struct nouveau_vma *);
......
#ifndef __NVBIOS_M0205_H__
#define __NVBIOS_M0205_H__
struct nvbios_M0205T {
u16 freq;
};
u32 nvbios_M0205Te(struct nouveau_bios *,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
u32 nvbios_M0205Tp(struct nouveau_bios *,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
struct nvbios_M0205T *);
struct nvbios_M0205E {
u8 type;
};
u32 nvbios_M0205Ee(struct nouveau_bios *, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u32 nvbios_M0205Ep(struct nouveau_bios *, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_M0205E *);
struct nvbios_M0205S {
u8 data;
};
u32 nvbios_M0205Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
u32 nvbios_M0205Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
struct nvbios_M0205S *);
#endif
#ifndef __NVBIOS_M0209_H__
#define __NVBIOS_M0209_H__
u32 nvbios_M0209Te(struct nouveau_bios *,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
struct nvbios_M0209E {
u8 v00_40;
u8 bits;
u8 modulo;
u8 v02_40;
u8 v02_07;
u8 v03;
};
u32 nvbios_M0209Ee(struct nouveau_bios *, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u32 nvbios_M0209Ep(struct nouveau_bios *, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_M0209E *);
struct nvbios_M0209S {
u32 data[0x200];
};
u32 nvbios_M0209Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
u32 nvbios_M0209Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
struct nvbios_M0209S *);
#endif
#ifndef __NVBIOS_FAN_H__
#define __NVBIOS_FAN_H__
#include <subdev/bios/therm.h>
u16 nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan);
#endif
......@@ -4,11 +4,55 @@
struct nouveau_bios;
struct nvbios_ramcfg {
unsigned rammap_ver;
unsigned rammap_hdr;
unsigned rammap_min;
unsigned rammap_max;
union {
struct {
unsigned rammap_10_04_02:1;
unsigned rammap_10_04_08:1;
};
struct {
unsigned rammap_11_08_01:1;
unsigned rammap_11_08_0c:2;
unsigned rammap_11_08_10:1;
unsigned rammap_11_09_01ff:9;
unsigned rammap_11_0a_03fe:9;
unsigned rammap_11_0a_0400:1;
unsigned rammap_11_0a_0800:1;
unsigned rammap_11_0b_01f0:5;
unsigned rammap_11_0b_0200:1;
unsigned rammap_11_0b_0400:1;
unsigned rammap_11_0b_0800:1;
unsigned rammap_11_0d:8;
unsigned rammap_11_0e:8;
unsigned rammap_11_0f:8;
unsigned rammap_11_11_0c:2;
};
};
unsigned ramcfg_ver;
unsigned ramcfg_hdr;
unsigned ramcfg_timing;
union {
struct {
unsigned ramcfg_10_02_01:1;
unsigned ramcfg_10_02_02:1;
unsigned ramcfg_10_02_04:1;
unsigned ramcfg_10_02_08:1;
unsigned ramcfg_10_02_10:1;
unsigned ramcfg_10_02_20:1;
unsigned ramcfg_10_02_40:1;
unsigned ramcfg_10_03_0f:4;
unsigned ramcfg_10_05:8;
unsigned ramcfg_10_06:8;
unsigned ramcfg_10_07:8;
unsigned ramcfg_10_08:8;
unsigned ramcfg_10_09_0f:4;
unsigned ramcfg_10_09_f0:4;
};
struct {
unsigned ramcfg_11_01_01:1;
unsigned ramcfg_11_01_02:1;
unsigned ramcfg_11_01_04:1;
......@@ -42,8 +86,20 @@ struct nvbios_ramcfg {
unsigned ramcfg_11_08_10:1;
unsigned ramcfg_11_08_20:1;
unsigned ramcfg_11_09:8;
};
};
unsigned timing_ver;
unsigned timing_hdr;
unsigned timing[11];
union {
struct {
unsigned timing_10_WR:8;
unsigned timing_10_CL:8;
unsigned timing_10_ODT:3;
unsigned timing_10_CWL:8;
};
struct {
unsigned timing_20_2e_03:2;
unsigned timing_20_2e_30:2;
unsigned timing_20_2e_c0:2;
......@@ -58,6 +114,8 @@ struct nvbios_ramcfg {
unsigned timing_20_31_0800:1;
unsigned timing_20_31_7000:3;
unsigned timing_20_31_8000:1;
};
};
};
u8 nvbios_ramcfg_count(struct nouveau_bios *);
......
......@@ -8,9 +8,10 @@ u32 nvbios_rammapTe(struct nouveau_bios *, u8 *ver, u8 *hdr,
u32 nvbios_rammapEe(struct nouveau_bios *, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u32 nvbios_rammapEp(struct nouveau_bios *, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_ramcfg *);
u32 nvbios_rammapEm(struct nouveau_bios *, u16 mhz,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u32 nvbios_rammapEp(struct nouveau_bios *, u16 mhz,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_ramcfg *);
......
......@@ -23,6 +23,12 @@ struct nvbios_therm_sensor {
struct nvbios_therm_threshold thrs_shutdown;
};
enum nvbios_therm_fan_type {
NVBIOS_THERM_FAN_UNK = 0,
NVBIOS_THERM_FAN_TOGGLE = 1,
NVBIOS_THERM_FAN_PWM = 2,
};
/* no vbios have more than 6 */
#define NOUVEAU_TEMP_FAN_TRIP_MAX 10
struct nouveau_therm_trip_point {
......@@ -38,7 +44,9 @@ enum nvbios_therm_fan_mode {
};
struct nvbios_therm_fan {
u16 pwm_freq;
enum nvbios_therm_fan_type type;
u32 pwm_freq;
u8 min_duty;
u8 max_duty;
......
......@@ -29,6 +29,7 @@ enum nv_clk_src {
nv_clk_src_mdiv,
nv_clk_src_core,
nv_clk_src_core_intm,
nv_clk_src_shader,
nv_clk_src_mem,
......
......@@ -111,6 +111,7 @@ extern struct nouveau_oclass *gm107_fb_oclass;
#include <subdev/bios/ramcfg.h>
struct nouveau_ram_data {
struct list_head head;
struct nvbios_ramcfg bios;
u32 freq;
};
......@@ -136,6 +137,7 @@ struct nouveau_ram {
int ranks;
int parts;
int part_mask;
int (*get)(struct nouveau_fb *, u64 size, u32 align,
u32 size_nc, u32 type, struct nouveau_mem **);
......@@ -144,11 +146,6 @@ struct nouveau_ram {
int (*calc)(struct nouveau_fb *, u32 freq);
int (*prog)(struct nouveau_fb *);
void (*tidy)(struct nouveau_fb *);
struct {
u8 version;
u32 data;
u8 size;
} rammap, ramcfg, timing;
u32 freq;
u32 mr[16];
u32 mr1_nuts;
......
#ifndef __NOUVEAU_FB_REGS_04_H__
#define __NOUVEAU_FB_REGS_04_H__
#define NV04_PFB_BOOT_0 0x00100000
# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
#endif
#ifndef __NOUVEAU_FUSE_H__
#define __NOUVEAU_FUSE_H__
#include <core/subdev.h>
#include <core/device.h>
struct nouveau_fuse {
struct nouveau_subdev base;
};
static inline struct nouveau_fuse *
nouveau_fuse(void *obj)
{
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FUSE];
}
#define nouveau_fuse_create(p, e, o, d) \
nouveau_fuse_create_((p), (e), (o), sizeof(**d), (void **)d)
int nouveau_fuse_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, void **);
void _nouveau_fuse_dtor(struct nouveau_object *);
int _nouveau_fuse_init(struct nouveau_object *);
#define _nouveau_fuse_fini _nouveau_subdev_fini
extern struct nouveau_oclass g80_fuse_oclass;
extern struct nouveau_oclass gf100_fuse_oclass;
extern struct nouveau_oclass gm107_fuse_oclass;
#endif
......@@ -40,7 +40,7 @@ nouveau_gpio(void *obj)
extern struct nouveau_oclass *nv10_gpio_oclass;
extern struct nouveau_oclass *nv50_gpio_oclass;
extern struct nouveau_oclass *nv92_gpio_oclass;
extern struct nouveau_oclass *nv94_gpio_oclass;
extern struct nouveau_oclass *nvd0_gpio_oclass;
extern struct nouveau_oclass *nve0_gpio_oclass;
......
......@@ -47,5 +47,8 @@ void nouveau_memx_wr32(struct nouveau_memx *, u32 addr, u32 data);
void nouveau_memx_wait(struct nouveau_memx *,
u32 addr, u32 mask, u32 data, u32 nsec);
void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
void nouveau_memx_wait_vblank(struct nouveau_memx *);
void nouveau_memx_block(struct nouveau_memx *);
void nouveau_memx_unblock(struct nouveau_memx *);
#endif
......@@ -78,5 +78,6 @@ extern struct nouveau_oclass nv50_therm_oclass;
extern struct nouveau_oclass nv84_therm_oclass;
extern struct nouveau_oclass nva3_therm_oclass;
extern struct nouveau_oclass nvd0_therm_oclass;
extern struct nouveau_oclass gm107_therm_oclass;
#endif
......@@ -38,10 +38,12 @@ struct nouveau_barobj {
static int
nouveau_barobj_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *mem, u32 size,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nouveau_bar *bar = (void *)engine;
struct nouveau_mem *mem = data;
struct nouveau_barobj *barobj;
int ret;
......@@ -54,7 +56,13 @@ nouveau_barobj_ctor(struct nouveau_object *parent,
if (ret)
return ret;
barobj->iomem = bar->iomem + (u32)barobj->vma.offset;
barobj->iomem = ioremap(nv_device_resource_start(device, 3) +
(u32)barobj->vma.offset, mem->size << 12);
if (!barobj->iomem) {
nv_warn(bar, "PRAMIN ioremap failed\n");
return -ENOMEM;
}
return 0;
}
......@@ -63,8 +71,11 @@ nouveau_barobj_dtor(struct nouveau_object *object)
{
struct nouveau_bar *bar = (void *)object->engine;
struct nouveau_barobj *barobj = (void *)object;
if (barobj->vma.node)
if (barobj->vma.node) {
if (barobj->iomem)
iounmap(barobj->iomem);
bar->unmap(bar, &barobj->vma);
}
nouveau_object_destroy(&barobj->base);
}
......@@ -99,12 +110,11 @@ nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
struct nouveau_mem *mem, struct nouveau_object **pobject)
{
struct nouveau_object *engine = nv_object(bar);
int ret = -ENOMEM;
if (bar->iomem) {
ret = nouveau_object_ctor(parent, engine,
&nouveau_barobj_oclass,
mem, 0, pobject);
}
struct nouveau_object *gpuobj;
int ret = nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
mem, 0, &gpuobj);
if (ret == 0)
*pobject = gpuobj;
return ret;
}
......@@ -113,7 +123,6 @@ nouveau_bar_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, int length, void **pobject)
{
struct nouveau_device *device = nv_device(parent);
struct nouveau_bar *bar;
int ret;
......@@ -123,21 +132,12 @@ nouveau_bar_create_(struct nouveau_object *parent,
if (ret)
return ret;
if (nv_device_resource_len(device, 3) != 0) {
bar->iomem = ioremap(nv_device_resource_start(device, 3),
nv_device_resource_len(device, 3));
if (!bar->iomem)
nv_warn(bar, "PRAMIN ioremap failed\n");
}
return 0;
}
void
nouveau_bar_destroy(struct nouveau_bar *bar)
{
if (bar->iomem)
iounmap(bar->iomem);
nouveau_subdev_destroy(&bar->base);
}
......
/*
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/M0205.h>
u32
nvbios_M0205Te(struct nouveau_bios *bios,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
{
struct bit_entry bit_M;
u32 data = 0x00000000;
if (!bit_entry(bios, 'M', &bit_M)) {
if (bit_M.version == 2 && bit_M.length > 0x08)
data = nv_ro32(bios, bit_M.offset + 0x05);
if (data) {
*ver = nv_ro08(bios, data + 0x00);
switch (*ver) {
case 0x10:
*hdr = nv_ro08(bios, data + 0x01);
*len = nv_ro08(bios, data + 0x02);
*ssz = nv_ro08(bios, data + 0x03);
*snr = nv_ro08(bios, data + 0x04);
*cnt = nv_ro08(bios, data + 0x05);
return data;
default:
break;
}
}
}
return 0x00000000;
}
u32
nvbios_M0205Tp(struct nouveau_bios *bios,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
struct nvbios_M0205T *info)
{
u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, snr, ssz);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x10:
info->freq = nv_ro16(bios, data + 0x06);
break;
default:
break;
}
return data;
}
u32
nvbios_M0205Ee(struct nouveau_bios *bios, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
u8 snr, ssz;
u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, &snr, &ssz);
if (data && idx < *cnt) {
data = data + *hdr + idx * (*len + (snr * ssz));
*hdr = *len;
*cnt = snr;
*len = ssz;
return data;
}
return 0x00000000;
}
u32
nvbios_M0205Ep(struct nouveau_bios *bios, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_M0205E *info)
{
u32 data = nvbios_M0205Ee(bios, idx, ver, hdr, cnt, len);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x10:
info->type = nv_ro08(bios, data + 0x00) & 0x0f;
return data;
default:
break;
}
return 0x00000000;
}
u32
nvbios_M0205Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
{
u8 cnt, len;
u32 data = nvbios_M0205Ee(bios, ent, ver, hdr, &cnt, &len);
if (data && idx < cnt) {
data = data + *hdr + idx * len;
*hdr = len;
return data;
}
return 0x00000000;
}
u32
nvbios_M0205Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
struct nvbios_M0205S *info)
{
u32 data = nvbios_M0205Se(bios, ent, idx, ver, hdr);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x10:
info->data = nv_ro08(bios, data + 0x00);
return data;
default:
break;
}
return 0x00000000;
}
/*
* Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/M0209.h>
u32
nvbios_M0209Te(struct nouveau_bios *bios,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
{
struct bit_entry bit_M;
u32 data = 0x00000000;
if (!bit_entry(bios, 'M', &bit_M)) {
if (bit_M.version == 2 && bit_M.length > 0x0c)
data = nv_ro32(bios, bit_M.offset + 0x09);
if (data) {
*ver = nv_ro08(bios, data + 0x00);
switch (*ver) {
case 0x10:
*hdr = nv_ro08(bios, data + 0x01);
*len = nv_ro08(bios, data + 0x02);
*ssz = nv_ro08(bios, data + 0x03);
*snr = 1;
*cnt = nv_ro08(bios, data + 0x04);
return data;
default:
break;
}
}
}
return 0x00000000;
}
u32
nvbios_M0209Ee(struct nouveau_bios *bios, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
u8 snr, ssz;
u32 data = nvbios_M0209Te(bios, ver, hdr, cnt, len, &snr, &ssz);
if (data && idx < *cnt) {
data = data + *hdr + idx * (*len + (snr * ssz));
*hdr = *len;
*cnt = snr;
*len = ssz;
return data;
}
return 0x00000000;
}
u32
nvbios_M0209Ep(struct nouveau_bios *bios, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_M0209E *info)
{
u32 data = nvbios_M0209Ee(bios, idx, ver, hdr, cnt, len);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x10:
info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6;
info->bits = nv_ro08(bios, data + 0x00) & 0x3f;
info->modulo = nv_ro08(bios, data + 0x01);
info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
info->v02_07 = nv_ro08(bios, data + 0x02) & 0x07;
info->v03 = nv_ro08(bios, data + 0x03);
return data;
default:
break;
}
return 0x00000000;
}
u32
nvbios_M0209Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
{
u8 cnt, len;
u32 data = nvbios_M0209Ee(bios, ent, ver, hdr, &cnt, &len);
if (data && idx < cnt) {
data = data + *hdr + idx * len;
*hdr = len;
return data;
}
return 0x00000000;
}
u32
nvbios_M0209Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
struct nvbios_M0209S *info)
{
struct nvbios_M0209E M0209E;
u8 cnt, len;
u32 data = nvbios_M0209Ep(bios, ent, ver, hdr, &cnt, &len, &M0209E);
if (data) {
u32 i, data = nvbios_M0209Se(bios, ent, idx, ver, hdr);
memset(info, 0x00, sizeof(*info));
switch (!!data * *ver) {
case 0x10:
for (i = 0; i < ARRAY_SIZE(info->data); i++) {
u32 bits = (i % M0209E.modulo) * M0209E.bits;
u32 mask = (1ULL << M0209E.bits) - 1;
u16 off = bits / 8;
u8 mod = bits % 8;
info->data[i] = nv_ro32(bios, data + off);
info->data[i] = info->data[i] >> mod;
info->data[i] = info->data[i] & mask;
}
return data;
default:
break;
}
}
return 0x00000000;
}
......@@ -124,6 +124,7 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
struct dcb_output *outp)
{
u16 dcb = dcb_outp(bios, idx, ver, len);
memset(outp, 0x00, sizeof(*outp));
if (dcb) {
if (*ver >= 0x20) {
u32 conn = nv_ro32(bios, dcb + 0x00);
......
/*
* Copyright 2014 Martin Peres
*
* 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: Martin Peres
*/
#include <subdev/bios.h>
#include <subdev/bios/bit.h>
#include <subdev/bios/fan.h>
u16
nvbios_fan_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
struct bit_entry bit_P;
u16 fan = 0x0000;
if (!bit_entry(bios, 'P', &bit_P)) {
if (bit_P.version == 2 && bit_P.length >= 0x5a)
fan = nv_ro16(bios, bit_P.offset + 0x58);
if (fan) {
*ver = nv_ro08(bios, fan + 0);
switch (*ver) {
case 0x10:
*hdr = nv_ro08(bios, fan + 1);
*len = nv_ro08(bios, fan + 2);
*cnt = nv_ro08(bios, fan + 3);
return fan;
default:
break;
}
}
}
return 0x0000;
}
u16
nvbios_fan_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
u8 *cnt, u8 *len)
{
u16 data = nvbios_fan_table(bios, ver, hdr, cnt, len);
if (data && idx < *cnt)
return data + *hdr + (idx * (*len));
return 0x0000;
}
u16
nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan)
{
u8 ver, hdr, cnt, len;
u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len);
if (data) {
u8 type = nv_ro08(bios, data + 0x00);
switch (type) {
case 0:
fan->type = NVBIOS_THERM_FAN_TOGGLE;
break;
case 1:
case 2:
/* TODO: Understand the difference between the two! */
fan->type = NVBIOS_THERM_FAN_PWM;
break;
default:
fan->type = NVBIOS_THERM_FAN_UNK;
}
fan->min_duty = nv_ro08(bios, data + 0x02);
fan->max_duty = nv_ro08(bios, data + 0x03);
fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff;
}
return data;
}
......@@ -75,31 +75,39 @@ nvbios_rammapEe(struct nouveau_bios *bios, int idx,
}
u32
nvbios_rammapEm(struct nouveau_bios *bios, u16 khz,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
int idx = 0;
u32 data;
while ((data = nvbios_rammapEe(bios, idx++, ver, hdr, cnt, len))) {
if (khz >= nv_ro16(bios, data + 0x00) &&
khz <= nv_ro16(bios, data + 0x02))
break;
}
return data;
}
u32
nvbios_rammapEp(struct nouveau_bios *bios, u16 khz,
nvbios_rammapEp(struct nouveau_bios *bios, int idx,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_ramcfg *p)
{
u32 data = nvbios_rammapEm(bios, khz, ver, hdr, cnt, len);
u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp;
memset(p, 0x00, sizeof(*p));
p->rammap_ver = *ver;
p->rammap_hdr = *hdr;
switch (!!data * *ver) {
case 0x10:
p->rammap_min = nv_ro16(bios, data + 0x00);
p->rammap_max = nv_ro16(bios, data + 0x02);
p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1;
p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3;
break;
case 0x11:
p->rammap_min = nv_ro16(bios, data + 0x00);
p->rammap_max = nv_ro16(bios, data + 0x02);
p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2;
p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
temp = nv_ro32(bios, data + 0x09);
p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0;
p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9;
p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18;
p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19;
p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20;
p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25;
p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26;
p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27;
p->rammap_11_0d = nv_ro08(bios, data + 0x0d);
p->rammap_11_0e = nv_ro08(bios, data + 0x0e);
p->rammap_11_0f = nv_ro08(bios, data + 0x0f);
p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2;
break;
default:
......@@ -109,6 +117,20 @@ nvbios_rammapEp(struct nouveau_bios *bios, u16 khz,
return data;
}
u32
nvbios_rammapEm(struct nouveau_bios *bios, u16 mhz,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_ramcfg *info)
{
int idx = 0;
u32 data;
while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) {
if (mhz >= info->rammap_min && mhz <= info->rammap_max)
break;
}
return data;
}
u32
nvbios_rammapSe(struct nouveau_bios *bios, u32 data,
u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
......@@ -129,8 +151,28 @@ nvbios_rammapSp(struct nouveau_bios *bios, u32 data,
u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
{
data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
p->ramcfg_ver = *ver;
p->ramcfg_hdr = *hdr;
switch (!!data * *ver) {
case 0x10:
p->ramcfg_timing = nv_ro08(bios, data + 0x01);
p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0;
p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1;
p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
p->ramcfg_10_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0;
p->ramcfg_10_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0;
p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0;
p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4;
break;
case 0x11:
p->ramcfg_timing = nv_ro08(bios, data + 0x00);
p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0;
p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1;
p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2;
......
......@@ -89,7 +89,15 @@ nvbios_timingEp(struct nouveau_bios *bios, int idx,
struct nvbios_ramcfg *p)
{
u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp;
p->timing_ver = *ver;
p->timing_hdr = *hdr;
switch (!!data * *ver) {
case 0x10:
p->timing_10_WR = nv_ro08(bios, data + 0x00);
p->timing_10_CL = nv_ro08(bios, data + 0x02);
p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07;
p->timing_10_CWL = nv_ro08(bios, data + 0x13);
break;
case 0x20:
p->timing[0] = nv_ro32(bios, data + 0x00);
p->timing[1] = nv_ro32(bios, data + 0x04);
......
......@@ -573,7 +573,7 @@ nouveau_clock_create_(struct nouveau_object *parent,
clk->allow_reclock = allow_reclock;
ret = nvkm_notify_init(&device->event, nouveau_clock_pwrsrc, true,
ret = nvkm_notify_init(NULL, &device->event, nouveau_clock_pwrsrc, true,
NULL, 0, 0, &clk->pwrsrc_ntfy);
if (ret)
return ret;
......
......@@ -6,9 +6,15 @@
struct nva3_clock_info {
u32 clk;
u32 pll;
enum {
NVA3_HOST_277,
NVA3_HOST_CLK,
} host_out;
u32 fb_delay;
};
int nva3_clock_info(struct nouveau_clock *, int, u32, u32,
int nva3_pll_info(struct nouveau_clock *, int, u32, u32,
struct nva3_clock_info *);
int nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags);
void nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags);
#endif
......@@ -28,6 +28,7 @@
#include <subdev/timer.h>
#include <subdev/clock.h>
#include "nva3.h"
#include "pll.h"
struct nvaa_clock_priv {
......@@ -299,25 +300,14 @@ static int
nvaa_clock_prog(struct nouveau_clock *clk)
{
struct nvaa_clock_priv *priv = (void *)clk;
struct nouveau_fifo *pfifo = nouveau_fifo(clk);
u32 pllmask = 0, mast;
unsigned long flags;
u32 pllmask = 0, mast, ptherm_gate;
int ret = -EBUSY;
/* halt and idle execution engines */
ptherm_gate = nv_mask(clk, 0x020060, 0x00070000, 0x00000000);
nv_mask(clk, 0x002504, 0x00000001, 0x00000001);
/* Wait until the interrupt handler is finished */
if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000))
goto resume;
if (pfifo)
pfifo->pause(pfifo, &flags);
unsigned long *f = &flags;
int ret = 0;
if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
goto resume;
if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
goto resume;
ret = nva3_clock_pre(clk, f);
if (ret)
goto out;
/* First switch to safe clocks: href */
mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640);
......@@ -375,15 +365,8 @@ nvaa_clock_prog(struct nouveau_clock *clk)
}
nv_wr32(clk, 0xc054, mast);
ret = 0;
resume:
if (pfifo)
pfifo->start(pfifo, &flags);
nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
nv_wr32(clk, 0x020060, ptherm_gate);
/* Disable some PLLs and dividers when unused */
if (priv->csrc != nv_clk_src_core) {
nv_wr32(clk, 0x4040, 0x00000000);
......@@ -395,6 +378,12 @@ nvaa_clock_prog(struct nouveau_clock *clk)
nv_mask(clk, 0x4020, 0x80000000, 0x00000000);
}
out:
if (ret == -EBUSY)
f = NULL;
nva3_clock_post(clk, f);
return ret;
}
......
......@@ -26,22 +26,8 @@
#include <core/device.h>
#define NV04_PFB_BOOT_0 0x00100000
# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
#include <subdev/fb/regsnv04.h>
#define NV04_PFB_DEBUG_0 0x00100080
# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001
# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010
......
......@@ -40,7 +40,7 @@ nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
int WL, CL, WR, at[2], dt, ds;
int rq = ram->freq < 1000000; /* XXX */
switch (ram->ramcfg.version) {
switch (ram->next->bios.ramcfg_ver) {
case 0x11:
pd = ram->next->bios.ramcfg_11_01_80;
lf = ram->next->bios.ramcfg_11_01_40;
......@@ -54,7 +54,7 @@ nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
return -ENOSYS;
}
switch (ram->timing.version) {
switch (ram->next->bios.timing_ver) {
case 0x20:
WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
CL = (ram->next->bios.timing[1] & 0x0000001f);
......
......@@ -45,7 +45,7 @@ nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
else tile->zcomp = 0x04000000; /* Z24S8 */
tile->zcomp |= tile->tag->offset;
......
......@@ -32,7 +32,7 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
else tile->zcomp = 0x00200000; /* Z24S8 */
tile->zcomp |= tile->tag->offset;
......
......@@ -51,7 +51,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
else tile->zcomp |= 0x02000000; /* Z24S8 */
tile->zcomp |= ((tile->tag->offset ) >> 6);
......
......@@ -32,7 +32,7 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
else tile->zcomp |= 0x08000000; /* Z24S8 */
tile->zcomp |= ((tile->tag->offset ) >> 6);
......
......@@ -32,7 +32,7 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
else tile->zcomp |= 0x20000000; /* Z24S8 */
tile->zcomp |= ((tile->tag->offset ) >> 6);
......
......@@ -33,7 +33,7 @@ nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
u32 tiles = DIV_ROUND_UP(size, 0x80);
u32 tags = round_up(tiles / pfb->ram->parts, 0x100);
if ( (flags & 2) &&
!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */
tile->zcomp |= ((tile->tag->offset ) >> 8);
tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
......
......@@ -35,6 +35,7 @@ extern struct nouveau_oclass nve0_ram_oclass;
extern struct nouveau_oclass gk20a_ram_oclass;
extern struct nouveau_oclass gm107_ram_oclass;
int nouveau_sddr2_calc(struct nouveau_ram *ram);
int nouveau_sddr3_calc(struct nouveau_ram *ram);
int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
......
......@@ -12,16 +12,32 @@ struct ramfuc {
struct ramfuc_reg {
int sequence;
bool force;
u32 addr[2];
u32 addr;
u32 stride; /* in bytes */
u32 mask;
u32 data;
};
static inline struct ramfuc_reg
ramfuc_stride(u32 addr, u32 stride, u32 mask)
{
return (struct ramfuc_reg) {
.sequence = 0,
.addr = addr,
.stride = stride,
.mask = mask,
.data = 0xdeadbeef,
};
}
static inline struct ramfuc_reg
ramfuc_reg2(u32 addr1, u32 addr2)
{
return (struct ramfuc_reg) {
.sequence = 0,
.addr = { addr1, addr2 },
.addr = addr1,
.stride = addr2 - addr1,
.mask = 0x3,
.data = 0xdeadbeef,
};
}
......@@ -29,7 +45,13 @@ ramfuc_reg2(u32 addr1, u32 addr2)
static noinline struct ramfuc_reg
ramfuc_reg(u32 addr)
{
return ramfuc_reg2(addr, addr);
return (struct ramfuc_reg) {
.sequence = 0,
.addr = addr,
.stride = 0,
.mask = 0x1,
.data = 0xdeadbeef,
};
}
static inline int
......@@ -62,18 +84,25 @@ static inline u32
ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
{
if (reg->sequence != ram->sequence)
reg->data = nv_rd32(ram->pfb, reg->addr[0]);
reg->data = nv_rd32(ram->pfb, reg->addr);
return reg->data;
}
static inline void
ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
{
unsigned int mask, off = 0;
reg->sequence = ram->sequence;
reg->data = data;
if (reg->addr[0] != reg->addr[1])
nouveau_memx_wr32(ram->memx, reg->addr[1], reg->data);
nouveau_memx_wr32(ram->memx, reg->addr[0], reg->data);
for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
if (mask & 1) {
nouveau_memx_wr32(ram->memx, reg->addr+off, reg->data);
}
off += reg->stride;
}
}
static inline void
......@@ -105,14 +134,35 @@ ramfuc_nsec(struct ramfuc *ram, u32 nsec)
nouveau_memx_nsec(ram->memx, nsec);
}
static inline void
ramfuc_wait_vblank(struct ramfuc *ram)
{
nouveau_memx_wait_vblank(ram->memx);
}
static inline void
ramfuc_block(struct ramfuc *ram)
{
nouveau_memx_block(ram->memx);
}
static inline void
ramfuc_unblock(struct ramfuc *ram)
{
nouveau_memx_unblock(ram->memx);
}
#define ram_init(s,p) ramfuc_init(&(s)->base, (p))
#define ram_exec(s,e) ramfuc_exec(&(s)->base, (e))
#define ram_have(s,r) ((s)->r_##r.addr[0] != 0x000000)
#define ram_have(s,r) ((s)->r_##r.addr != 0x000000)
#define ram_rd32(s,r) ramfuc_rd32(&(s)->base, &(s)->r_##r)
#define ram_wr32(s,r,d) ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
#define ram_nuke(s,r) ramfuc_nuke(&(s)->base, &(s)->r_##r)
#define ram_mask(s,r,m,d) ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n))
#define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base)
#define ram_block(s) ramfuc_block(&(s)->base)
#define ram_unblock(s) ramfuc_unblock(&(s)->base)
#endif
......@@ -22,22 +22,7 @@
* Authors: Ben Skeggs
*/
#define NV04_PFB_BOOT_0 0x00100000
# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
#include <subdev/fb/regsnv04.h>
#include "priv.h"
......
......@@ -280,7 +280,7 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
if (align == 16) {
int n = (max >> 4) * comp;
ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
ret = nouveau_mm_head(tags, 0, 1, n, n, 1, &mem->tag);
if (ret)
mem->tag = NULL;
}
......@@ -296,9 +296,9 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
type = nv50_fb_memtype[type];
do {
if (back)
ret = nouveau_mm_tail(heap, type, max, min, align, &r);
ret = nouveau_mm_tail(heap, 0, type, max, min, align, &r);
else
ret = nouveau_mm_head(heap, type, max, min, align, &r);
ret = nouveau_mm_head(heap, 0, type, max, min, align, &r);
if (ret) {
mutex_unlock(&pfb->base.mutex);
pfb->ram->put(pfb, &mem);
......@@ -319,27 +319,22 @@ nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
static u32
nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
{
int i, parts, colbits, rowbitsa, rowbitsb, banks;
int colbits, rowbitsa, rowbitsb, banks;
u64 rowsize, predicted;
u32 r0, r4, rt, ru, rblock_size;
u32 r0, r4, rt, rblock_size;
r0 = nv_rd32(pfb, 0x100200);
r4 = nv_rd32(pfb, 0x100204);
rt = nv_rd32(pfb, 0x100250);
ru = nv_rd32(pfb, 0x001540);
nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
for (i = 0, parts = 0; i < 8; i++) {
if (ru & (0x00010000 << i))
parts++;
}
nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt,
nv_rd32(pfb, 0x001540));
colbits = (r4 & 0x0000f000) >> 12;
rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
rowsize = parts * banks * (1 << colbits) * 8;
rowsize = ram->parts * banks * (1 << colbits) * 8;
predicted = rowsize << rowbitsa;
if (r0 & 0x00000004)
predicted += rowsize << rowbitsb;
......@@ -376,6 +371,9 @@ nv50_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
ram->size = nv_rd32(pfb, 0x10020c);
ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16;
ram->parts = hweight8(ram->part_mask);
switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
case 0: ram->type = NV_MEM_TYPE_DDR1; break;
case 1:
......
......@@ -79,20 +79,27 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
struct nva3_ram *ram = (void *)pfb->ram;
struct nva3_ramfuc *fuc = &ram->fuc;
struct nva3_clock_info mclk;
u8 ver, cnt, len, strap;
struct nouveau_ram_data *next;
u8 ver, hdr, cnt, len, strap;
u32 data;
struct {
u32 data;
u8 size;
} rammap, ramcfg, timing;
u32 r004018, r100760, ctrl;
u32 unk714, unk718, unk71c;
int ret;
int ret, i;
next = &ram->base.target;
next->freq = freq;
ram->base.next = next;
/* lookup memory config data relevant to the target frequency */
rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
&cnt, &ramcfg.size);
if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
i = 0;
while ((data = nvbios_rammapEp(bios, i++, &ver, &hdr, &cnt, &len,
&next->bios))) {
if (freq / 1000 >= next->bios.rammap_min &&
freq / 1000 <= next->bios.rammap_max)
break;
}
if (!data || ver != 0x10 || hdr < 0x0e) {
nv_error(pfb, "invalid/missing rammap entry\n");
return -EINVAL;
}
......@@ -104,26 +111,25 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
return -EINVAL;
}
ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
&ver, &hdr, &next->bios);
if (!data || ver != 0x10 || hdr < 0x0e) {
nv_error(pfb, "invalid/missing ramcfg entry\n");
return -EINVAL;
}
/* lookup memory timings, if bios says they're present */
strap = nv_ro08(bios, ramcfg.data + 0x01);
if (strap != 0xff) {
timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
&cnt, &len);
if (!timing.data || ver != 0x10 || timing.size < 0x19) {
if (next->bios.ramcfg_timing != 0xff) {
data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
&ver, &hdr, &cnt, &len,
&next->bios);
if (!data || ver != 0x10 || hdr < 0x19) {
nv_error(pfb, "invalid/missing timing entry\n");
return -EINVAL;
}
} else {
timing.data = 0;
}
ret = nva3_clock_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk);
ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk);
if (ret < 0) {
nv_error(pfb, "failed mclk calculation\n");
return ret;
......@@ -163,17 +169,17 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
ram_mask(fuc, 0x004168, 0x003f3141, ctrl);
}
if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) {
if (next->bios.ramcfg_10_02_10) {
ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
} else {
ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
}
if (!(nv_ro08(bios, rammap.data + 0x04) & 0x02))
if (!next->bios.rammap_10_04_02)
ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
ram_wr32(fuc, 0x611200, 0x00003300);
if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x10))
if (!next->bios.ramcfg_10_02_10)
ram_wr32(fuc, 0x111100, 0x4c020000); /*XXX*/
ram_wr32(fuc, 0x1002d4, 0x00000001);
......@@ -202,17 +208,16 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
ram_wr32(fuc, 0x004018, 0x0000d000 | r004018);
}
if ( (nv_ro08(bios, rammap.data + 0x04) & 0x08)) {
u32 unk5a0 = (nv_ro16(bios, ramcfg.data + 0x05) << 8) |
nv_ro08(bios, ramcfg.data + 0x05);
u32 unk5a4 = (nv_ro16(bios, ramcfg.data + 0x07));
u32 unk804 = (nv_ro08(bios, ramcfg.data + 0x09) & 0xf0) << 16 |
(nv_ro08(bios, ramcfg.data + 0x03) & 0x0f) << 16 |
(nv_ro08(bios, ramcfg.data + 0x09) & 0x0f) |
0x80000000;
ram_wr32(fuc, 0x1005a0, unk5a0);
ram_wr32(fuc, 0x1005a4, unk5a4);
ram_wr32(fuc, 0x10f804, unk804);
if (next->bios.rammap_10_04_08) {
ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
next->bios.ramcfg_10_05 << 8 |
next->bios.ramcfg_10_05);
ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 |
next->bios.ramcfg_10_07);
ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 |
next->bios.ramcfg_10_03_0f << 16 |
next->bios.ramcfg_10_09_0f |
0x80000000);
ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
} else {
ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
......@@ -250,27 +255,26 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
ram_mask(fuc, 0x100220[0], 0x00000000, 0x00000000);
ram_mask(fuc, 0x100220[8], 0x00000000, 0x00000000);
data = (nv_ro08(bios, ramcfg.data + 0x02) & 0x08) ? 0x00000000 : 0x00001000;
ram_mask(fuc, 0x100200, 0x00001000, data);
ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000010;
unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100;
unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100;
if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x20))
if (next->bios.ramcfg_10_02_20)
unk714 |= 0xf0000000;
if (!(nv_ro08(bios, ramcfg.data + 0x02) & 0x04))
if (!next->bios.ramcfg_10_02_04)
unk714 |= 0x00000010;
ram_wr32(fuc, 0x100714, unk714);
if (nv_ro08(bios, ramcfg.data + 0x02) & 0x01)
if (next->bios.ramcfg_10_02_01)
unk71c |= 0x00000100;
ram_wr32(fuc, 0x10071c, unk71c);
if (nv_ro08(bios, ramcfg.data + 0x02) & 0x02)
if (next->bios.ramcfg_10_02_02)
unk718 |= 0x00000100;
ram_wr32(fuc, 0x100718, unk718);
if (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)
if (next->bios.ramcfg_10_02_10)
ram_wr32(fuc, 0x111100, 0x48000000); /*XXX*/
ram_mask(fuc, mr[0], 0x100, 0x100);
......@@ -282,9 +286,9 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
ram_nsec(fuc, 12000);
ram_wr32(fuc, 0x611200, 0x00003330);
if ( (nv_ro08(bios, rammap.data + 0x04) & 0x02))
if (next->bios.rammap_10_04_02)
ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
if ( (nv_ro08(bios, ramcfg.data + 0x02) & 0x10)) {
if (next->bios.ramcfg_10_02_10) {
ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
} else {
......@@ -404,11 +408,11 @@ nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
ram->fuc.r_0x100760 = ramfuc_reg(0x100760);
ram->fuc.r_0x1007a0 = ramfuc_reg(0x1007a0);
ram->fuc.r_0x1007e0 = ramfuc_reg(0x1007e0);
ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
ram->fuc.r_0x1110e0 = ramfuc_reg(0x1110e0);
ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
......
......@@ -133,6 +133,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
struct nouveau_bios *bios = nouveau_bios(pfb);
struct nvc0_ram *ram = (void *)pfb->ram;
struct nvc0_ramfuc *fuc = &ram->fuc;
struct nvbios_ramcfg cfg;
u8 ver, cnt, len, strap;
struct {
u32 data;
......@@ -145,7 +146,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
/* lookup memory config data relevant to the target frequency */
rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
&cnt, &ramcfg.size);
&cnt, &ramcfg.size, &cfg);
if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
nv_error(pfb, "invalid/missing rammap entry\n");
return -EINVAL;
......@@ -483,9 +484,9 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
do {
if (back)
ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
ret = nouveau_mm_tail(mm, 0, 1, size, ncmin, align, &r);
else
ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
ret = nouveau_mm_head(mm, 0, 1, size, ncmin, align, &r);
if (ret) {
mutex_unlock(&pfb->base.mutex);
pfb->ram->put(pfb, &mem);
......@@ -562,7 +563,7 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
offset = (0x0200000000ULL >> 12) + (bsize << 8);
length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
if (ret)
nouveau_mm_fini(&pfb->vram);
}
......
/*
* Copyright 2014 Roy Spliet
*
* 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: Roy Spliet <rspliet@eclipso.eu>
* Ben Skeggs
*/
#include "priv.h"
struct ramxlat {
int id;
u8 enc;
};
static inline int
ramxlat(const struct ramxlat *xlat, int id)
{
while (xlat->id >= 0) {
if (xlat->id == id)
return xlat->enc;
xlat++;
}
return -EINVAL;
}
static const struct ramxlat
ramddr2_cl[] = {
{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
/* The following are available in some, but not all DDR2 docs */
{ 7, 7 },
{ -1 }
};
static const struct ramxlat
ramddr2_wr[] = {
{ 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 },
/* The following are available in some, but not all DDR2 docs */
{ 7, 6 },
{ -1 }
};
int
nouveau_sddr2_calc(struct nouveau_ram *ram)
{
int CL, WR, DLL = 0, ODT = 0;
switch (ram->next->bios.timing_ver) {
case 0x10:
CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR;
DLL = !ram->next->bios.ramcfg_10_02_40;
ODT = ram->next->bios.timing_10_ODT & 3;
break;
case 0x20:
CL = (ram->next->bios.timing[1] & 0x0000001f);
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
break;
default:
return -ENOSYS;
}
CL = ramxlat(ramddr2_cl, CL);
WR = ramxlat(ramddr2_wr, WR);
if (CL < 0 || WR < 0)
return -EINVAL;
ram->mr[0] &= ~0xf70;
ram->mr[0] |= (WR & 0x07) << 9;
ram->mr[0] |= (CL & 0x07) << 4;
ram->mr[1] &= ~0x045;
ram->mr[1] |= (ODT & 0x1) << 2;
ram->mr[1] |= (ODT & 0x2) << 5;
ram->mr[1] |= !DLL;
return 0;
}
......@@ -20,9 +20,9 @@
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs <bskeggs@redhat.com>
* Roy Spliet <rspliet@eclipso.eu>
*/
#include <subdev/bios.h>
#include "priv.h"
struct ramxlat {
......@@ -69,31 +69,52 @@ ramddr3_cwl[] = {
int
nouveau_sddr3_calc(struct nouveau_ram *ram)
{
struct nouveau_bios *bios = nouveau_bios(ram);
int WL, CL, WR;
int CWL, CL, WR, DLL = 0, ODT = 0;
switch (!!ram->timing.data * ram->timing.version) {
switch (ram->next->bios.timing_ver) {
case 0x10:
if (ram->next->bios.timing_hdr < 0x17) {
/* XXX: NV50: Get CWL from the timing register */
return -ENOSYS;
}
CWL = ram->next->bios.timing_10_CWL;
CL = ram->next->bios.timing_10_CL;
WR = ram->next->bios.timing_10_WR;
DLL = !ram->next->bios.ramcfg_10_02_40;
ODT = ram->next->bios.timing_10_ODT;
break;
case 0x20:
WL = (nv_ro16(bios, ram->timing.data + 0x04) & 0x0f80) >> 7;
CL = nv_ro08(bios, ram->timing.data + 0x04) & 0x1f;
WR = nv_ro08(bios, ram->timing.data + 0x0a) & 0x7f;
CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
/* XXX: Get these values from the VBIOS instead */
DLL = !(ram->mr[1] & 0x1);
ODT = (ram->mr[1] & 0x004) >> 2 |
(ram->mr[1] & 0x040) >> 5 |
(ram->mr[1] & 0x200) >> 7;
break;
default:
return -ENOSYS;
}
WL = ramxlat(ramddr3_cwl, WL);
CWL = ramxlat(ramddr3_cwl, CWL);
CL = ramxlat(ramddr3_cl, CL);
WR = ramxlat(ramddr3_wr, WR);
if (WL < 0 || CL < 0 || WR < 0)
if (CL < 0 || CWL < 0 || WR < 0)
return -EINVAL;
ram->mr[0] &= ~0xe74;
ram->mr[0] &= ~0xf74;
ram->mr[0] |= (WR & 0x07) << 9;
ram->mr[0] |= (CL & 0x0e) << 3;
ram->mr[0] |= (CL & 0x01) << 2;
ram->mr[1] &= ~0x245;
ram->mr[1] |= (ODT & 0x1) << 2;
ram->mr[1] |= (ODT & 0x2) << 5;
ram->mr[1] |= (ODT & 0x4) << 7;
ram->mr[1] |= !DLL;
ram->mr[2] &= ~0x038;
ram->mr[2] |= (WL & 0x07) << 3;
ram->mr[2] |= (CWL & 0x07) << 3;
return 0;
}
/*
* Copyright 2014 Martin Peres
*
* 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: Martin Peres
*/
#include <subdev/fuse.h>
int
_nouveau_fuse_init(struct nouveau_object *object)
{
struct nouveau_fuse *fuse = (void *)object;
return nouveau_subdev_init(&fuse->base);
}
void
_nouveau_fuse_dtor(struct nouveau_object *object)
{
struct nouveau_fuse *fuse = (void *)object;
nouveau_subdev_destroy(&fuse->base);
}
int
nouveau_fuse_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, int length, void **pobject)
{
struct nouveau_fuse *fuse;
int ret;
ret = nouveau_subdev_create_(parent, engine, oclass, 0, "FUSE",
"fuse", length, pobject);
fuse = *pobject;
return ret;
}
/*
* Copyright 2014 Martin Peres
*
* 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: Martin Peres
*/
#include "priv.h"
struct g80_fuse_priv {
struct nouveau_fuse base;
spinlock_t fuse_enable_lock;
};
static u32
g80_fuse_rd32(struct nouveau_object *object, u64 addr)
{
struct g80_fuse_priv *priv = (void *)object;
unsigned long flags;
u32 fuse_enable, val;
spin_lock_irqsave(&priv->fuse_enable_lock, flags);
/* racy if another part of nouveau start writing to this reg */
fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800);
val = nv_rd32(priv, 0x21000 + addr);
nv_wr32(priv, 0x1084, fuse_enable);
spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
return val;
}
static int
g80_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct g80_fuse_priv *priv;
int ret;
ret = nouveau_fuse_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
spin_lock_init(&priv->fuse_enable_lock);
return 0;
}
struct nouveau_oclass
g80_fuse_oclass = {
.handle = NV_SUBDEV(FUSE, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = g80_fuse_ctor,
.dtor = _nouveau_fuse_dtor,
.init = _nouveau_fuse_init,
.fini = _nouveau_fuse_fini,
.rd32 = g80_fuse_rd32,
},
};
/*
* Copyright 2014 Martin Peres
*
* 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: Martin Peres
*/
#include "priv.h"
struct gf100_fuse_priv {
struct nouveau_fuse base;
spinlock_t fuse_enable_lock;
};
static u32
gf100_fuse_rd32(struct nouveau_object *object, u64 addr)
{
struct gf100_fuse_priv *priv = (void *)object;
unsigned long flags;
u32 fuse_enable, unk, val;
spin_lock_irqsave(&priv->fuse_enable_lock, flags);
/* racy if another part of nouveau start writing to these regs */
fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800);
unk = nv_mask(priv, 0x21000, 0x1, 0x1);
val = nv_rd32(priv, 0x21100 + addr);
nv_wr32(priv, 0x21000, unk);
nv_wr32(priv, 0x22400, fuse_enable);
spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
return val;
}
static int
gf100_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct gf100_fuse_priv *priv;
int ret;
ret = nouveau_fuse_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
spin_lock_init(&priv->fuse_enable_lock);
return 0;
}
struct nouveau_oclass
gf100_fuse_oclass = {
.handle = NV_SUBDEV(FUSE, 0xC0),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = gf100_fuse_ctor,
.dtor = _nouveau_fuse_dtor,
.init = _nouveau_fuse_init,
.fini = _nouveau_fuse_fini,
.rd32 = gf100_fuse_rd32,
},
};
/*
* Copyright 2014 Martin Peres
*
* 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: Martin Peres
*/
#include "priv.h"
struct gm107_fuse_priv {
struct nouveau_fuse base;
};
static u32
gm107_fuse_rd32(struct nouveau_object *object, u64 addr)
{
struct gf100_fuse_priv *priv = (void *)object;
return nv_rd32(priv, 0x21100 + addr);
}
static int
gm107_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct gm107_fuse_priv *priv;
int ret;
ret = nouveau_fuse_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
return 0;
}
struct nouveau_oclass
gm107_fuse_oclass = {
.handle = NV_SUBDEV(FUSE, 0x117),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = gm107_fuse_ctor,
.dtor = _nouveau_fuse_dtor,
.init = _nouveau_fuse_init,
.fini = _nouveau_fuse_fini,
.rd32 = gm107_fuse_rd32,
},
};
#ifndef __NVKM_FUSE_PRIV_H__
#define __NVKM_FUSE_PRIV_H__
#include <subdev/fuse.h>
int _nouveau_fuse_init(struct nouveau_object *object);
void _nouveau_fuse_dtor(struct nouveau_object *object);
#endif
......@@ -122,7 +122,8 @@ nouveau_gpio_intr_init(struct nvkm_event *event, int type, int index)
}
static int
nouveau_gpio_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
nouveau_gpio_intr_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nvkm_gpio_ntfy_req *req = data;
if (!WARN_ON(size != sizeof(*req))) {
......
......@@ -25,7 +25,7 @@
#include "priv.h"
void
nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
nv94_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
{
u32 intr0 = nv_rd32(gpio, 0x00e054);
u32 intr1 = nv_rd32(gpio, 0x00e074);
......@@ -38,7 +38,7 @@ nv92_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
}
void
nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
nv94_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);
......@@ -57,8 +57,8 @@ nv92_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
}
struct nouveau_oclass *
nv92_gpio_oclass = &(struct nouveau_gpio_impl) {
.base.handle = NV_SUBDEV(GPIO, 0x92),
nv94_gpio_oclass = &(struct nouveau_gpio_impl) {
.base.handle = NV_SUBDEV(GPIO, 0x94),
.base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = _nouveau_gpio_ctor,
.dtor = _nouveau_gpio_dtor,
......@@ -66,8 +66,8 @@ nv92_gpio_oclass = &(struct nouveau_gpio_impl) {
.fini = _nouveau_gpio_fini,
},
.lines = 32,
.intr_stat = nv92_gpio_intr_stat,
.intr_mask = nv92_gpio_intr_mask,
.intr_stat = nv94_gpio_intr_stat,
.intr_mask = nv94_gpio_intr_mask,
.drive = nv50_gpio_drive,
.sense = nv50_gpio_sense,
.reset = nv50_gpio_reset,
......
......@@ -77,8 +77,8 @@ nvd0_gpio_oclass = &(struct nouveau_gpio_impl) {
.fini = _nouveau_gpio_fini,
},
.lines = 32,
.intr_stat = nv92_gpio_intr_stat,
.intr_mask = nv92_gpio_intr_mask,
.intr_stat = nv94_gpio_intr_stat,
.intr_mask = nv94_gpio_intr_mask,
.drive = nvd0_gpio_drive,
.sense = nvd0_gpio_sense,
.reset = nvd0_gpio_reset,
......
......@@ -56,8 +56,8 @@ void nv50_gpio_reset(struct nouveau_gpio *, u8);
int nv50_gpio_drive(struct nouveau_gpio *, int, int, int);
int nv50_gpio_sense(struct nouveau_gpio *, int);
void nv92_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *);
void nv92_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32);
void nv94_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *);
void nv94_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32);
void nvd0_gpio_reset(struct nouveau_gpio *, u8);
int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int);
......
......@@ -23,6 +23,7 @@
*/
#include <core/option.h>
#include <core/object.h>
#include <core/event.h>
#include <subdev/bios.h>
......@@ -346,7 +347,8 @@ nouveau_i2c_intr_init(struct nvkm_event *event, int type, int index)
}
static int
nouveau_i2c_intr_ctor(void *data, u32 size, struct nvkm_notify *notify)
nouveau_i2c_intr_ctor(struct nouveau_object *object, void *data, u32 size,
struct nvkm_notify *notify)
{
struct nvkm_i2c_ntfy_req *req = data;
if (!WARN_ON(size != sizeof(*req))) {
......
......@@ -69,7 +69,7 @@ nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
ret = nouveau_mm_head(&priv->heap, 1, args->size, args->size,
ret = nouveau_mm_head(&priv->heap, 0, 1, args->size, args->size,
args->align, &node->mem);
if (ret)
return ret;
......
......@@ -31,7 +31,7 @@ nvkm_ltc_tags_alloc(struct nouveau_ltc *ltc, u32 n,
struct nvkm_ltc_priv *priv = (void *)ltc;
int ret;
ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode);
ret = nouveau_mm_head(&priv->tags, 0, 1, n, n, 1, pnode);
if (ret)
*pnode = NULL;
......
......@@ -62,16 +62,38 @@ gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
nv_wr32(priv, 0x17ea58, depth);
}
static const struct nouveau_bitfield
gf100_ltc_lts_intr_name[] = {
{ 0x00000001, "IDLE_ERROR_IQ" },
{ 0x00000002, "IDLE_ERROR_CBC" },
{ 0x00000004, "IDLE_ERROR_TSTG" },
{ 0x00000008, "IDLE_ERROR_DSTG" },
{ 0x00000010, "EVICTED_CB" },
{ 0x00000020, "ILLEGAL_COMPSTAT" },
{ 0x00000040, "BLOCKLINEAR_CB" },
{ 0x00000100, "ECC_SEC_ERROR" },
{ 0x00000200, "ECC_DED_ERROR" },
{ 0x00000400, "DEBUG" },
{ 0x00000800, "ATOMIC_TO_Z" },
{ 0x00001000, "ILLEGAL_ATOMIC" },
{ 0x00002000, "BLKACTIVITY_ERR" },
{}
};
static void
gf100_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts)
gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts)
{
u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
u32 stat = nv_rd32(priv, base + 0x020);
u32 intr = nv_rd32(priv, base + 0x020);
u32 stat = intr & 0x0000ffff;
if (stat) {
nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
nv_wr32(priv, base + 0x020, stat);
nv_info(priv, "LTC%d_LTS%d:", ltc, lts);
nouveau_bitfield_print(gf100_ltc_lts_intr_name, stat);
pr_cont("\n");
}
nv_wr32(priv, base + 0x020, intr);
}
void
......@@ -84,14 +106,9 @@ gf100_ltc_intr(struct nouveau_subdev *subdev)
while (mask) {
u32 lts, ltc = __ffs(mask);
for (lts = 0; lts < priv->lts_nr; lts++)
gf100_ltc_lts_isr(priv, ltc, lts);
gf100_ltc_lts_intr(priv, ltc, lts);
mask &= ~(1 << ltc);
}
/* we do something horribly wrong and upset PMFB a lot, so mask off
* interrupts from it after the first one until it's fixed
*/
nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
}
static int
......@@ -151,7 +168,7 @@ gf100_ltc_init_tag_ram(struct nouveau_fb *pfb, struct nvkm_ltc_priv *priv)
tag_size += tag_align;
tag_size = (tag_size + 0xfff) >> 12; /* round up */
ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1,
ret = nouveau_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1,
&priv->tag_ram);
if (ret) {
priv->num_tags = 0;
......
......@@ -87,11 +87,6 @@ gm107_ltc_intr(struct nouveau_subdev *subdev)
gm107_ltc_lts_isr(priv, ltc, lts);
mask &= ~(1 << ltc);
}
/* we do something horribly wrong and upset PMFB a lot, so mask off
* interrupts from it after the first one until it's fixed
*/
nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
}
static int
......
......@@ -4,6 +4,8 @@
#include <subdev/ltc.h>
#include <subdev/fb.h>
#include <core/enum.h>
struct nvkm_ltc_priv {
struct nouveau_ltc base;
u32 ltc_nr;
......
......@@ -203,6 +203,8 @@ _nouveau_pwr_init(struct nouveau_object *object)
nv_wait(ppwr, 0x10a04c, 0xffffffff, 0x00000000);
nv_mask(ppwr, 0x000200, 0x00002000, 0x00000000);
nv_mask(ppwr, 0x000200, 0x00002000, 0x00002000);
nv_rd32(ppwr, 0x000200);
nv_wait(ppwr, 0x10a10c, 0x00000006, 0x00000000);
/* upload data segment */
nv_wr32(ppwr, 0x10a1c0, 0x01000000);
......
/*
* Copyright 2014 Martin Peres <martin.peres@free.fr>
*
* 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 folloing 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: Martin Peres
*/
/******************************************************************************
* arith data segment
*****************************************************************************/
#ifdef INCLUDE_PROC
#endif
#ifdef INCLUDE_DATA
#endif
/******************************************************************************
* arith code segment
*****************************************************************************/
#ifdef INCLUDE_CODE
// does a 32x32 -> 64 multiplication
//
// A * B = A_lo * B_lo
// + ( A_hi * B_lo ) << 16
// + ( A_lo * B_hi ) << 16
// + ( A_hi * B_hi ) << 32
//
// $r15 - current
// $r14 - A
// $r13 - B
// $r12 - mul_lo (return)
// $r11 - mul_hi (return)
// $r0 - zero
mulu32_32_64:
push $r1 // A_hi
push $r2 // B_hi
push $r3 // tmp0
push $r4 // tmp1
shr b32 $r1 $r14 16
shr b32 $r2 $r13 16
clear b32 $r12
clear b32 $r11
// A_lo * B_lo
mulu $r12 $r14 $r13
// ( A_hi * B_lo ) << 16
mulu $r3 $r1 $r13 // tmp0 = A_hi * B_lo
mov b32 $r4 $r3
and $r3 0xffff // tmp0 = tmp0_lo
shl b32 $r3 16
shr b32 $r4 16 // tmp1 = tmp0_hi
add b32 $r12 $r3
adc b32 $r11 $r4
// ( A_lo * B_hi ) << 16
mulu $r3 $r14 $r2 // tmp0 = A_lo * B_hi
mov b32 $r4 $r3
and $r3 0xffff // tmp0 = tmp0_lo
shl b32 $r3 16
shr b32 $r4 16 // tmp1 = tmp0_hi
add b32 $r12 $r3
adc b32 $r11 $r4
// ( A_hi * B_hi ) << 32
mulu $r3 $r1 $r2 // tmp0 = A_hi * B_hi
add b32 $r11 $r3
pop $r4
pop $r3
pop $r2
pop $r1
ret
#endif
......@@ -98,12 +98,16 @@ wr32:
// $r14 - ns
// $r0 - zero
nsec:
push $r9
push $r8
nv_iord($r8, NV_PPWR_TIMER_LOW)
nsec_loop:
nv_iord($r9, NV_PPWR_TIMER_LOW)
sub b32 $r9 $r8
cmp b32 $r9 $r14
bra l #nsec_loop
pop $r8
pop $r9
ret
// busy-wait for a period of time
......@@ -115,6 +119,8 @@ nsec:
// $r11 - timeout (ns)
// $r0 - zero
wait:
push $r9
push $r8
nv_iord($r8, NV_PPWR_TIMER_LOW)
wait_loop:
nv_rd32($r10, $r14)
......@@ -126,6 +132,8 @@ wait:
cmp b32 $r9 $r11
bra l #wait_loop
wait_done:
pop $r8
pop $r9
ret
// $r15 - current (kern)
......@@ -242,12 +250,89 @@ intr:
bclr $flags $p0
iret
// request the current process be sent a message after a timeout expires
// calculate the number of ticks in the specified nanoseconds delay
//
// $r15 - current
// $r14 - ns
// $r14 - ticks (return)
// $r0 - zero
ticks_from_ns:
push $r12
push $r11
/* try not losing precision (multiply then divide) */
imm32($r13, HW_TICKS_PER_US)
call #mulu32_32_64
/* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */
div $r12 $r12 1000
/* check if there wasn't any overflow */
cmpu b32 $r11 0
bra e #ticks_from_ns_quit
/* let's divide then multiply, too bad for the precision! */
div $r14 $r14 1000
imm32($r13, HW_TICKS_PER_US)
call #mulu32_32_64
/* this cannot overflow as long as HW_TICKS_PER_US < 1000 */
ticks_from_ns_quit:
mov b32 $r14 $r12
pop $r11
pop $r12
ret
// calculate the number of ticks in the specified microsecond delay
//
// $r15 - current
// $r14 - us
// $r14 - ticks (return)
// $r0 - zero
ticks_from_us:
push $r12
push $r11
/* simply multiply $us by HW_TICKS_PER_US */
imm32($r13, HW_TICKS_PER_US)
call #mulu32_32_64
mov b32 $r14 $r12
/* check if there wasn't any overflow */
cmpu b32 $r11 0
bra e #ticks_from_us_quit
/* Overflow! */
clear b32 $r14
ticks_from_us_quit:
pop $r11
pop $r12
ret
// calculate the number of ticks in the specified microsecond delay
//
// $r15 - current
// $r14 - ticks
// $r14 - us (return)
// $r0 - zero
ticks_to_us:
/* simply divide $ticks by HW_TICKS_PER_US */
imm32($r13, HW_TICKS_PER_US)
div $r14 $r14 $r13
ret
// request the current process be sent a message after a timeout expires
//
// $r15 - current
// $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
// $r0 - zero
timer:
push $r9
push $r8
// interrupts off to prevent racing with timer isr
bclr $flags ie0
......@@ -255,13 +340,22 @@ timer:
ld b32 $r8 D[$r15 + #proc_time]
cmp b32 $r8 0
bra g #timer_done
st b32 D[$r15 + #proc_time] $r14
// halt watchdog timer temporarily and check for a pending
// interrupt. if there's one already pending, we can just
// bail since the timer isr will queue the next soonest
// right after it's done
// halt watchdog timer temporarily
clear b32 $r8
nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
// find out how much time elapsed since the last update
// of the watchdog and add this time to the wanted ticks
nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
ld b32 $r9 D[$r0 + #time_prev]
sub b32 $r9 $r8
add b32 $r14 $r9
st b32 D[$r15 + #proc_time] $r14
// check for a pending interrupt. if there's one already
// pending, we can just bail since the timer isr will
// queue the next soonest right after it's done
nv_iord($r8, NV_PPWR_INTR)
and $r8 NV_PPWR_INTR_WATCHDOG
bra nz #timer_enable
......@@ -272,7 +366,7 @@ timer:
cmp b32 $r14 $r0
bra e #timer_reset
cmp b32 $r14 $r8
bra l #timer_done
bra g #timer_enable
timer_reset:
nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
st b32 D[$r0 + #time_prev] $r14
......@@ -285,6 +379,9 @@ timer:
// interrupts back on
timer_done:
bset $flags ie0
pop $r8
pop $r9
ret
// send message to another process
......@@ -371,6 +468,9 @@ send:
// $r14 - process
// $r0 - zero
recv:
push $r9
push $r8
ld b32 $r8 D[$r14 + #proc_qget]
ld b32 $r9 D[$r14 + #proc_qput]
bclr $flags $p1
......@@ -403,6 +503,8 @@ recv:
bset $flags $p1
pop $r15
recv_done:
pop $r8
pop $r9
ret
init:
......
......@@ -250,3 +250,23 @@
*/ st b32 D[$r0] reg /*
*/ clear b32 $r0
#endif
#define st(size, addr, reg) /*
*/ movw $r0 addr /*
*/ st size D[$r0] reg /*
*/ clear b32 $r0
#define ld(size, reg, addr) /*
*/ movw $r0 addr /*
*/ ld size reg D[$r0] /*
*/ clear b32 $r0
// does a 64+64 -> 64 unsigned addition (C = A + B)
#define addu64(reg_a_c_hi, reg_a_c_lo, b_hi, b_lo) /*
*/ add b32 reg_a_c_lo b_lo /*
*/ adc b32 reg_a_c_hi b_hi
// does a 64+64 -> 64 substraction (C = A - B)
#define subu64(reg_a_c_hi, reg_a_c_lo, b_hi, b_lo) /*
*/ sub b32 reg_a_c_lo b_lo /*
*/ sbb b32 reg_a_c_hi b_hi
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment