mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-25 21:54:06 +08:00
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 ...
This commit is contained in:
commit
4ac073640a
@ -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, ¬ify->n);
|
||||
ret = nvkm_notify_init(object, event, nvkm_client_notify,
|
||||
false, data, size, reply, ¬ify->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);
|
||||
int nodes = 0;
|
||||
struct nouveau_mm_node *node, *temp;
|
||||
int nodes = 0;
|
||||
|
||||
list_for_each_entry(node, &mm->nodes, nl_entry) {
|
||||
if (WARN_ON(nodes++ == mm->heap_nodes))
|
||||
if (!nouveau_mm_initialised(mm))
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(node, &mm->nodes, nl_entry) {
|
||||
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;
|
||||
}
|
||||
|
83
drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c
Normal file
83
drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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;
|
||||
u64 value;
|
||||
|
||||
/* calculate packed data rate for each lane */
|
||||
if (dpctrl > 0x00030000) link_nr = 4;
|
||||
else if (dpctrl > 0x00010000) link_nr = 2;
|
||||
else link_nr = 1;
|
||||
link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
|
||||
link_nr = hweight32(dpctrl & 0x000f0000);
|
||||
|
||||
if (clksor & 0x000c0000)
|
||||
link_bw = 270000;
|
||||
else
|
||||
link_bw = 162000;
|
||||
/* 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 *);
|
||||
|
32
drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h
Normal file
32
drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h
Normal file
@ -0,0 +1,32 @@
|
||||
#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
|
30
drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h
Normal file
30
drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h
Normal file
@ -0,0 +1,30 @@
|
||||
#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
|
8
drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h
Normal file
8
drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h
Normal file
@ -0,0 +1,8 @@
|
||||
#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,60 +4,118 @@
|
||||
struct nouveau_bios;
|
||||
|
||||
struct nvbios_ramcfg {
|
||||
unsigned rammap_11_08_01:1;
|
||||
unsigned rammap_11_08_0c:2;
|
||||
unsigned rammap_11_08_10:1;
|
||||
unsigned rammap_11_11_0c:2;
|
||||
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_11_01_01:1;
|
||||
unsigned ramcfg_11_01_02:1;
|
||||
unsigned ramcfg_11_01_04:1;
|
||||
unsigned ramcfg_11_01_08:1;
|
||||
unsigned ramcfg_11_01_10:1;
|
||||
unsigned ramcfg_11_01_20:1;
|
||||
unsigned ramcfg_11_01_40:1;
|
||||
unsigned ramcfg_11_01_80:1;
|
||||
unsigned ramcfg_11_02_03:2;
|
||||
unsigned ramcfg_11_02_04:1;
|
||||
unsigned ramcfg_11_02_08:1;
|
||||
unsigned ramcfg_11_02_10:1;
|
||||
unsigned ramcfg_11_02_40:1;
|
||||
unsigned ramcfg_11_02_80:1;
|
||||
unsigned ramcfg_11_03_0f:4;
|
||||
unsigned ramcfg_11_03_30:2;
|
||||
unsigned ramcfg_11_03_c0:2;
|
||||
unsigned ramcfg_11_03_f0:4;
|
||||
unsigned ramcfg_11_04:8;
|
||||
unsigned ramcfg_11_06:8;
|
||||
unsigned ramcfg_11_07_02:1;
|
||||
unsigned ramcfg_11_07_04:1;
|
||||
unsigned ramcfg_11_07_08:1;
|
||||
unsigned ramcfg_11_07_10:1;
|
||||
unsigned ramcfg_11_07_40:1;
|
||||
unsigned ramcfg_11_07_80:1;
|
||||
unsigned ramcfg_11_08_01:1;
|
||||
unsigned ramcfg_11_08_02:1;
|
||||
unsigned ramcfg_11_08_04:1;
|
||||
unsigned ramcfg_11_08_08:1;
|
||||
unsigned ramcfg_11_08_10:1;
|
||||
unsigned ramcfg_11_08_20:1;
|
||||
unsigned ramcfg_11_09:8;
|
||||
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;
|
||||
unsigned ramcfg_11_01_08:1;
|
||||
unsigned ramcfg_11_01_10:1;
|
||||
unsigned ramcfg_11_01_20:1;
|
||||
unsigned ramcfg_11_01_40:1;
|
||||
unsigned ramcfg_11_01_80:1;
|
||||
unsigned ramcfg_11_02_03:2;
|
||||
unsigned ramcfg_11_02_04:1;
|
||||
unsigned ramcfg_11_02_08:1;
|
||||
unsigned ramcfg_11_02_10:1;
|
||||
unsigned ramcfg_11_02_40:1;
|
||||
unsigned ramcfg_11_02_80:1;
|
||||
unsigned ramcfg_11_03_0f:4;
|
||||
unsigned ramcfg_11_03_30:2;
|
||||
unsigned ramcfg_11_03_c0:2;
|
||||
unsigned ramcfg_11_03_f0:4;
|
||||
unsigned ramcfg_11_04:8;
|
||||
unsigned ramcfg_11_06:8;
|
||||
unsigned ramcfg_11_07_02:1;
|
||||
unsigned ramcfg_11_07_04:1;
|
||||
unsigned ramcfg_11_07_08:1;
|
||||
unsigned ramcfg_11_07_10:1;
|
||||
unsigned ramcfg_11_07_40:1;
|
||||
unsigned ramcfg_11_07_80:1;
|
||||
unsigned ramcfg_11_08_01:1;
|
||||
unsigned ramcfg_11_08_02:1;
|
||||
unsigned ramcfg_11_08_04:1;
|
||||
unsigned ramcfg_11_08_08:1;
|
||||
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];
|
||||
unsigned timing_20_2e_03:2;
|
||||
unsigned timing_20_2e_30:2;
|
||||
unsigned timing_20_2e_c0:2;
|
||||
unsigned timing_20_2f_03:2;
|
||||
unsigned timing_20_2c_003f:6;
|
||||
unsigned timing_20_2c_1fc0:7;
|
||||
unsigned timing_20_30_f8:5;
|
||||
unsigned timing_20_30_07:3;
|
||||
unsigned timing_20_31_0007:3;
|
||||
unsigned timing_20_31_0078:4;
|
||||
unsigned timing_20_31_0780:4;
|
||||
unsigned timing_20_31_0800:1;
|
||||
unsigned timing_20_31_7000:3;
|
||||
unsigned timing_20_31_8000:1;
|
||||
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;
|
||||
unsigned timing_20_2f_03:2;
|
||||
unsigned timing_20_2c_003f:6;
|
||||
unsigned timing_20_2c_1fc0:7;
|
||||
unsigned timing_20_30_f8:5;
|
||||
unsigned timing_20_30_07:3;
|
||||
unsigned timing_20_31_0007:3;
|
||||
unsigned timing_20_31_0078:4;
|
||||
unsigned timing_20_31_0780:4;
|
||||
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;
|
||||
|
21
drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h
Normal file
21
drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h
Normal file
@ -0,0 +1,21 @@
|
||||
#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
|
30
drivers/gpu/drm/nouveau/core/include/subdev/fuse.h
Normal file
30
drivers/gpu/drm/nouveau/core/include/subdev/fuse.h
Normal file
@ -0,0 +1,30 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
|
136
drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c
Normal file
136
drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
137
drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c
Normal file
137
drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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);
|
||||
|
93
drivers/gpu/drm/nouveau/core/subdev/bios/fan.c
Normal file
93
drivers/gpu/drm/nouveau/core/subdev/bios/fan.c
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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;
|
||||
|
@ -20,8 +20,10 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: Ben Skeggs
|
||||
* Roy Spliet
|
||||
*/
|
||||
|
||||
#include <engine/fifo.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/pll.h>
|
||||
#include <subdev/timer.h>
|
||||
@ -42,9 +44,17 @@ static u32
|
||||
read_vco(struct nva3_clock_priv *priv, int clk)
|
||||
{
|
||||
u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4));
|
||||
if ((sctl & 0x00000030) != 0x00000030)
|
||||
|
||||
switch (sctl & 0x00000030) {
|
||||
case 0x00000000:
|
||||
return nv_device(priv)->crystal;
|
||||
case 0x00000020:
|
||||
return read_pll(priv, 0x41, 0x00e820);
|
||||
return read_pll(priv, 0x42, 0x00e8a0);
|
||||
case 0x00000030:
|
||||
return read_pll(priv, 0x42, 0x00e8a0);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u32
|
||||
@ -66,14 +76,25 @@ read_clk(struct nva3_clock_priv *priv, int clk, bool ignore_en)
|
||||
if (!ignore_en && !(sctl & 0x00000100))
|
||||
return 0;
|
||||
|
||||
/* out_alt */
|
||||
if (sctl & 0x00000400)
|
||||
return 108000;
|
||||
|
||||
/* vco_out */
|
||||
switch (sctl & 0x00003000) {
|
||||
case 0x00000000:
|
||||
return nv_device(priv)->crystal;
|
||||
if (!(sctl & 0x00000200))
|
||||
return nv_device(priv)->crystal;
|
||||
return 0;
|
||||
case 0x00002000:
|
||||
if (sctl & 0x00000040)
|
||||
return 108000;
|
||||
return 100000;
|
||||
case 0x00003000:
|
||||
/* vco_enable */
|
||||
if (!(sctl & 0x00000001))
|
||||
return 0;
|
||||
|
||||
sclk = read_vco(priv, clk);
|
||||
sdiv = ((sctl & 0x003f0000) >> 16) + 2;
|
||||
return (sclk * 2) / sdiv;
|
||||
@ -95,7 +116,9 @@ read_pll(struct nva3_clock_priv *priv, int clk, u32 pll)
|
||||
N = (coef & 0x0000ff00) >> 8;
|
||||
P = (coef & 0x003f0000) >> 16;
|
||||
|
||||
/* no post-divider on these.. */
|
||||
/* no post-divider on these..
|
||||
* XXX: it looks more like two post-"dividers" that
|
||||
* cross each other out in the default RPLL config */
|
||||
if ((pll & 0x00ff00) == 0x00e800)
|
||||
P = 1;
|
||||
|
||||
@ -114,13 +137,13 @@ static int
|
||||
nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
|
||||
{
|
||||
struct nva3_clock_priv *priv = (void *)clk;
|
||||
u32 hsrc;
|
||||
|
||||
switch (src) {
|
||||
case nv_clk_src_crystal:
|
||||
return nv_device(priv)->crystal;
|
||||
case nv_clk_src_href:
|
||||
return 100000;
|
||||
case nv_clk_src_core:
|
||||
case nv_clk_src_core_intm:
|
||||
return read_pll(priv, 0x00, 0x4200);
|
||||
case nv_clk_src_shader:
|
||||
return read_pll(priv, 0x01, 0x4220);
|
||||
@ -132,24 +155,33 @@ nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
|
||||
return read_clk(priv, 0x21, false);
|
||||
case nv_clk_src_daemon:
|
||||
return read_clk(priv, 0x25, false);
|
||||
case nv_clk_src_host:
|
||||
hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28;
|
||||
switch (hsrc) {
|
||||
case 0:
|
||||
return read_clk(priv, 0x1d, false);
|
||||
case 2:
|
||||
case 3:
|
||||
return 277000;
|
||||
default:
|
||||
nv_error(clk, "unknown HOST clock source %d\n", hsrc);
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
nv_error(clk, "invalid clock source %d\n", src);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
|
||||
nva3_clk_info(struct nouveau_clock *clock, int clk, u32 khz,
|
||||
struct nva3_clock_info *info)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(clock);
|
||||
struct nva3_clock_priv *priv = (void *)clock;
|
||||
struct nvbios_pll limits;
|
||||
u32 oclk, sclk, sdiv;
|
||||
int P, N, M, diff;
|
||||
int ret;
|
||||
u32 oclk, sclk, sdiv, diff;
|
||||
|
||||
info->pll = 0;
|
||||
info->clk = 0;
|
||||
|
||||
switch (khz) {
|
||||
@ -164,43 +196,69 @@ nva3_clock_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
|
||||
return khz;
|
||||
default:
|
||||
sclk = read_vco(priv, clk);
|
||||
sdiv = min((sclk * 2) / (khz - 2999), (u32)65);
|
||||
/* if the clock has a PLL attached, and we can get a within
|
||||
* [-2, 3) MHz of a divider, we'll disable the PLL and use
|
||||
* the divider instead.
|
||||
*
|
||||
* divider can go as low as 2, limited here because NVIDIA
|
||||
* and the VBIOS on my NVA8 seem to prefer using the PLL
|
||||
* for 810MHz - is there a good reason?
|
||||
*/
|
||||
if (sdiv > 4) {
|
||||
sdiv = min((sclk * 2) / khz, (u32)65);
|
||||
oclk = (sclk * 2) / sdiv;
|
||||
diff = ((khz + 3000) - oclk);
|
||||
|
||||
/* When imprecise, play it safe and aim for a clock lower than
|
||||
* desired rather than higher */
|
||||
if (diff < 0) {
|
||||
sdiv++;
|
||||
oclk = (sclk * 2) / sdiv;
|
||||
diff = khz - oclk;
|
||||
if (!pll || (diff >= -2000 && diff < 3000)) {
|
||||
info->clk = (((sdiv - 2) << 16) | 0x00003100);
|
||||
return oclk;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pll)
|
||||
return -ERANGE;
|
||||
/* divider can go as low as 2, limited here because NVIDIA
|
||||
* and the VBIOS on my NVA8 seem to prefer using the PLL
|
||||
* for 810MHz - is there a good reason?
|
||||
* XXX: PLLs with refclk 810MHz? */
|
||||
if (sdiv > 4) {
|
||||
info->clk = (((sdiv - 2) << 16) | 0x00003100);
|
||||
return oclk;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
int
|
||||
nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
|
||||
struct nva3_clock_info *info)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(clock);
|
||||
struct nva3_clock_priv *priv = (void *)clock;
|
||||
struct nvbios_pll limits;
|
||||
int P, N, M, diff;
|
||||
int ret;
|
||||
|
||||
info->pll = 0;
|
||||
|
||||
/* If we can get a within [-2, 3) MHz of a divider, we'll disable the
|
||||
* PLL and use the divider instead. */
|
||||
ret = nva3_clk_info(clock, clk, khz, info);
|
||||
diff = khz - ret;
|
||||
if (!pll || (diff >= -2000 && diff < 3000)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Try with PLL */
|
||||
ret = nvbios_pll_parse(bios, pll, &limits);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
limits.refclk = read_clk(priv, clk - 0x10, true);
|
||||
if (!limits.refclk)
|
||||
ret = nva3_clk_info(clock, clk - 0x10, limits.refclk, info);
|
||||
if (ret != limits.refclk)
|
||||
return -EINVAL;
|
||||
|
||||
ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
|
||||
if (ret >= 0) {
|
||||
info->clk = nv_rd32(priv, 0x4120 + (clk * 4));
|
||||
info->pll = (P << 16) | (N << 8) | M;
|
||||
}
|
||||
|
||||
out:
|
||||
info->fb_delay = max(((khz + 7566) / 15133), (u32) 18);
|
||||
|
||||
return ret ? ret : -ERANGE;
|
||||
}
|
||||
|
||||
@ -208,13 +266,76 @@ static int
|
||||
calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate,
|
||||
int clk, u32 pll, int idx)
|
||||
{
|
||||
int ret = nva3_clock_info(&priv->base, clk, pll, cstate->domain[idx],
|
||||
int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx],
|
||||
&priv->eng[idx]);
|
||||
if (ret >= 0)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
calc_host(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 kHz = cstate->domain[nv_clk_src_host];
|
||||
struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
|
||||
|
||||
if (kHz == 277000) {
|
||||
info->clk = 0;
|
||||
info->host_out = NVA3_HOST_277;
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->host_out = NVA3_HOST_CLK;
|
||||
|
||||
ret = nva3_clk_info(&priv->base, 0x1d, kHz, info);
|
||||
if (ret >= 0)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags)
|
||||
{
|
||||
struct nouveau_fifo *pfifo = nouveau_fifo(clk);
|
||||
|
||||
/* halt and idle execution engines */
|
||||
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))
|
||||
return -EBUSY;
|
||||
|
||||
if (pfifo)
|
||||
pfifo->pause(pfifo, flags);
|
||||
|
||||
if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
|
||||
return -EIO;
|
||||
if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags)
|
||||
{
|
||||
struct nouveau_fifo *pfifo = nouveau_fifo(clk);
|
||||
|
||||
if (pfifo && flags)
|
||||
pfifo->start(pfifo, flags);
|
||||
|
||||
nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
|
||||
nv_mask(clk, 0x020060, 0x00070000, 0x00040000);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_clk_src(struct nva3_clock_priv *priv, u32 src)
|
||||
{
|
||||
nv_mask(priv, src, 0x00000100, 0x00000000);
|
||||
nv_mask(priv, src, 0x00000001, 0x00000000);
|
||||
}
|
||||
|
||||
static void
|
||||
prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
|
||||
{
|
||||
@ -223,24 +344,35 @@ prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
|
||||
const u32 src1 = 0x004160 + (clk * 4);
|
||||
const u32 ctrl = pll + 0;
|
||||
const u32 coef = pll + 4;
|
||||
u32 bypass;
|
||||
|
||||
if (info->pll) {
|
||||
nv_mask(priv, src0, 0x00000101, 0x00000101);
|
||||
/* Always start from a non-PLL clock */
|
||||
bypass = nv_rd32(priv, ctrl) & 0x00000008;
|
||||
if (!bypass) {
|
||||
nv_mask(priv, src1, 0x00000101, 0x00000101);
|
||||
nv_mask(priv, ctrl, 0x00000008, 0x00000008);
|
||||
udelay(20);
|
||||
}
|
||||
|
||||
nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk);
|
||||
nv_wr32(priv, coef, info->pll);
|
||||
nv_mask(priv, ctrl, 0x00000015, 0x00000015);
|
||||
nv_mask(priv, ctrl, 0x00000010, 0x00000000);
|
||||
nv_wait(priv, ctrl, 0x00020000, 0x00020000);
|
||||
if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) {
|
||||
nv_mask(priv, ctrl, 0x00000010, 0x00000010);
|
||||
nv_mask(priv, src0, 0x00000101, 0x00000000);
|
||||
return;
|
||||
}
|
||||
nv_mask(priv, ctrl, 0x00000010, 0x00000010);
|
||||
nv_mask(priv, ctrl, 0x00000008, 0x00000000);
|
||||
nv_mask(priv, src1, 0x00000100, 0x00000000);
|
||||
nv_mask(priv, src1, 0x00000001, 0x00000000);
|
||||
disable_clk_src(priv, src1);
|
||||
} else {
|
||||
nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
|
||||
nv_mask(priv, ctrl, 0x00000018, 0x00000018);
|
||||
udelay(20);
|
||||
nv_mask(priv, ctrl, 0x00000001, 0x00000000);
|
||||
nv_mask(priv, src0, 0x00000100, 0x00000000);
|
||||
nv_mask(priv, src0, 0x00000001, 0x00000000);
|
||||
disable_clk_src(priv, src0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,18 +383,72 @@ prog_clk(struct nva3_clock_priv *priv, int clk, int idx)
|
||||
nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
|
||||
}
|
||||
|
||||
static void
|
||||
prog_host(struct nva3_clock_priv *priv)
|
||||
{
|
||||
struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
|
||||
u32 hsrc = (nv_rd32(priv, 0xc040));
|
||||
|
||||
switch (info->host_out) {
|
||||
case NVA3_HOST_277:
|
||||
if ((hsrc & 0x30000000) == 0) {
|
||||
nv_wr32(priv, 0xc040, hsrc | 0x20000000);
|
||||
disable_clk_src(priv, 0x4194);
|
||||
}
|
||||
break;
|
||||
case NVA3_HOST_CLK:
|
||||
prog_clk(priv, 0x1d, nv_clk_src_host);
|
||||
if ((hsrc & 0x30000000) >= 0x20000000) {
|
||||
nv_wr32(priv, 0xc040, hsrc & ~0x30000000);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* This seems to be a clock gating factor on idle, always set to 64 */
|
||||
nv_wr32(priv, 0xc044, 0x3e);
|
||||
}
|
||||
|
||||
static void
|
||||
prog_core(struct nva3_clock_priv *priv, int idx)
|
||||
{
|
||||
struct nva3_clock_info *info = &priv->eng[idx];
|
||||
u32 fb_delay = nv_rd32(priv, 0x10002c);
|
||||
|
||||
if (fb_delay < info->fb_delay)
|
||||
nv_wr32(priv, 0x10002c, info->fb_delay);
|
||||
|
||||
prog_pll(priv, 0x00, 0x004200, idx);
|
||||
|
||||
if (fb_delay > info->fb_delay)
|
||||
nv_wr32(priv, 0x10002c, info->fb_delay);
|
||||
}
|
||||
|
||||
static int
|
||||
nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
|
||||
{
|
||||
struct nva3_clock_priv *priv = (void *)clk;
|
||||
struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
|
||||
int ret;
|
||||
|
||||
if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
|
||||
(ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
|
||||
(ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
|
||||
(ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)))
|
||||
(ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) ||
|
||||
(ret = calc_host(priv, cstate)))
|
||||
return ret;
|
||||
|
||||
/* XXX: Should be reading the highest bit in the VBIOS clock to decide
|
||||
* whether to use a PLL or not... but using a PLL defeats the purpose */
|
||||
if (core->pll) {
|
||||
ret = nva3_clk_info(clk, 0x10,
|
||||
cstate->domain[nv_clk_src_core_intm],
|
||||
&priv->eng[nv_clk_src_core_intm]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -270,11 +456,31 @@ static int
|
||||
nva3_clock_prog(struct nouveau_clock *clk)
|
||||
{
|
||||
struct nva3_clock_priv *priv = (void *)clk;
|
||||
prog_pll(priv, 0x00, 0x004200, nv_clk_src_core);
|
||||
struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
unsigned long *f = &flags;
|
||||
|
||||
ret = nva3_clock_pre(clk, f);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (core->pll)
|
||||
prog_core(priv, nv_clk_src_core_intm);
|
||||
|
||||
prog_core(priv, nv_clk_src_core);
|
||||
prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
|
||||
prog_clk(priv, 0x20, nv_clk_src_disp);
|
||||
prog_clk(priv, 0x21, nv_clk_src_vdec);
|
||||
return 0;
|
||||
prog_host(priv);
|
||||
|
||||
out:
|
||||
if (ret == -EBUSY)
|
||||
f = NULL;
|
||||
|
||||
nva3_clock_post(clk, f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -284,13 +490,14 @@ nva3_clock_tidy(struct nouveau_clock *clk)
|
||||
|
||||
static struct nouveau_clocks
|
||||
nva3_domain[] = {
|
||||
{ nv_clk_src_crystal, 0xff },
|
||||
{ nv_clk_src_href , 0xff },
|
||||
{ nv_clk_src_core , 0x00, 0, "core", 1000 },
|
||||
{ nv_clk_src_shader , 0x01, 0, "shader", 1000 },
|
||||
{ nv_clk_src_mem , 0x02, 0, "memory", 1000 },
|
||||
{ nv_clk_src_vdec , 0x03 },
|
||||
{ nv_clk_src_disp , 0x04 },
|
||||
{ nv_clk_src_crystal , 0xff },
|
||||
{ nv_clk_src_core , 0x00, 0, "core", 1000 },
|
||||
{ nv_clk_src_shader , 0x01, 0, "shader", 1000 },
|
||||
{ nv_clk_src_mem , 0x02, 0, "memory", 1000 },
|
||||
{ nv_clk_src_vdec , 0x03 },
|
||||
{ nv_clk_src_disp , 0x04 },
|
||||
{ nv_clk_src_host , 0x05 },
|
||||
{ nv_clk_src_core_intm, 0x06 },
|
||||
{ nv_clk_src_max }
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
unsigned long *f = &flags;
|
||||
int ret = 0;
|
||||
|
||||
/* 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);
|
||||
|
||||
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 @@ resume:
|
||||
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);
|
||||
}
|
||||
|
||||
#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_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))
|
||||
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 != 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);
|
||||
}
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <subdev/bios/init.h>
|
||||
#include <subdev/bios/rammap.h>
|
||||
#include <subdev/bios/timing.h>
|
||||
#include <subdev/bios/M0205.h>
|
||||
#include <subdev/bios/M0209.h>
|
||||
|
||||
#include <subdev/clock.h>
|
||||
#include <subdev/clock/pll.h>
|
||||
@ -41,14 +43,6 @@
|
||||
|
||||
#include "ramfuc.h"
|
||||
|
||||
/* binary driver only executes this path if the condition (a) is true
|
||||
* for any configuration (combination of rammap+ramcfg+timing) that
|
||||
* can be reached on a given card. for now, we will execute the branch
|
||||
* unconditionally in the hope that a "false everywhere" in the bios
|
||||
* tables doesn't actually mean "don't touch this".
|
||||
*/
|
||||
#define NOTE00(a) 1
|
||||
|
||||
struct nve0_ramfuc {
|
||||
struct ramfuc base;
|
||||
|
||||
@ -134,10 +128,12 @@ struct nve0_ram {
|
||||
struct nouveau_ram base;
|
||||
struct nve0_ramfuc fuc;
|
||||
|
||||
struct list_head cfg;
|
||||
u32 parts;
|
||||
u32 pmask;
|
||||
u32 pnuts;
|
||||
|
||||
struct nvbios_ramcfg diff;
|
||||
int from;
|
||||
int mode;
|
||||
int N1, fN1, M1, P1;
|
||||
@ -241,7 +237,7 @@ nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
|
||||
{
|
||||
struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
|
||||
struct ramfuc *fuc = &ram->fuc.base;
|
||||
u32 addr = 0x110000 + (reg->addr[0] & 0xfff);
|
||||
u32 addr = 0x110000 + (reg->addr & 0xfff);
|
||||
u32 mask = _mask | _copy;
|
||||
u32 data = (_data & _mask) | (reg->data & _copy);
|
||||
u32 i;
|
||||
@ -268,6 +264,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
|
||||
u32 mask, data;
|
||||
|
||||
ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
|
||||
ram_block(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0000);
|
||||
|
||||
/* MR1: turn termination on early, for some reason.. */
|
||||
@ -478,7 +475,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
|
||||
ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
|
||||
|
||||
data = mask = 0x00000000;
|
||||
if (NOTE00(ramcfg_08_20)) {
|
||||
if (ram->diff.ramcfg_11_08_20) {
|
||||
if (next->bios.ramcfg_11_08_20)
|
||||
data |= 0x01000000;
|
||||
mask |= 0x01000000;
|
||||
@ -486,11 +483,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
|
||||
ram_mask(fuc, 0x10f200, mask, data);
|
||||
|
||||
data = mask = 0x00000000;
|
||||
if (NOTE00(ramcfg_02_03 != 0)) {
|
||||
if (ram->diff.ramcfg_11_02_03) {
|
||||
data |= next->bios.ramcfg_11_02_03 << 8;
|
||||
mask |= 0x00000300;
|
||||
}
|
||||
if (NOTE00(ramcfg_01_10)) {
|
||||
if (ram->diff.ramcfg_11_01_10) {
|
||||
if (next->bios.ramcfg_11_01_10)
|
||||
data |= 0x70000000;
|
||||
mask |= 0x70000000;
|
||||
@ -498,11 +495,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
|
||||
ram_mask(fuc, 0x10f604, mask, data);
|
||||
|
||||
data = mask = 0x00000000;
|
||||
if (NOTE00(timing_30_07 != 0)) {
|
||||
if (ram->diff.timing_20_30_07) {
|
||||
data |= next->bios.timing_20_30_07 << 28;
|
||||
mask |= 0x70000000;
|
||||
}
|
||||
if (NOTE00(ramcfg_01_01)) {
|
||||
if (ram->diff.ramcfg_11_01_01) {
|
||||
if (next->bios.ramcfg_11_01_01)
|
||||
data |= 0x00000100;
|
||||
mask |= 0x00000100;
|
||||
@ -510,11 +507,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
|
||||
ram_mask(fuc, 0x10f614, mask, data);
|
||||
|
||||
data = mask = 0x00000000;
|
||||
if (NOTE00(timing_30_07 != 0)) {
|
||||
if (ram->diff.timing_20_30_07) {
|
||||
data |= next->bios.timing_20_30_07 << 28;
|
||||
mask |= 0x70000000;
|
||||
}
|
||||
if (NOTE00(ramcfg_01_02)) {
|
||||
if (ram->diff.ramcfg_11_01_02) {
|
||||
if (next->bios.ramcfg_11_01_02)
|
||||
data |= 0x00000100;
|
||||
mask |= 0x00000100;
|
||||
@ -548,11 +545,11 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
|
||||
ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
|
||||
|
||||
data = mask = 0x00000000;
|
||||
if (NOTE00(ramcfg_02_03 != 0)) {
|
||||
if (ram->diff.ramcfg_11_02_03) {
|
||||
data |= next->bios.ramcfg_11_02_03;
|
||||
mask |= 0x00000003;
|
||||
}
|
||||
if (NOTE00(ramcfg_01_10)) {
|
||||
if (ram->diff.ramcfg_11_01_10) {
|
||||
if (next->bios.ramcfg_11_01_10)
|
||||
data |= 0x00000004;
|
||||
mask |= 0x00000004;
|
||||
@ -666,6 +663,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
|
||||
if (next->bios.ramcfg_11_07_02)
|
||||
nve0_ram_train(fuc, 0x80020000, 0x01000000);
|
||||
|
||||
ram_unblock(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
|
||||
|
||||
if (next->bios.rammap_11_08_01)
|
||||
@ -695,6 +693,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
|
||||
u32 mask, data;
|
||||
|
||||
ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
|
||||
ram_block(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0000);
|
||||
|
||||
if (vc == 1 && ram_have(fuc, gpio2E)) {
|
||||
@ -917,6 +916,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
|
||||
ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
|
||||
ram_nsec(fuc, 1000);
|
||||
|
||||
ram_unblock(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
|
||||
|
||||
if (next->bios.rammap_11_08_01)
|
||||
@ -932,58 +932,24 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
|
||||
******************************************************************************/
|
||||
|
||||
static int
|
||||
nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq,
|
||||
nve0_ram_calc_data(struct nouveau_fb *pfb, u32 khz,
|
||||
struct nouveau_ram_data *data)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(pfb);
|
||||
struct nve0_ram *ram = (void *)pfb->ram;
|
||||
u8 strap, cnt, len;
|
||||
struct nouveau_ram_data *cfg;
|
||||
u32 mhz = khz / 1000;
|
||||
|
||||
/* lookup memory config data relevant to the target frequency */
|
||||
ram->base.rammap.data = nvbios_rammapEp(bios, freq / 1000,
|
||||
&ram->base.rammap.version,
|
||||
&ram->base.rammap.size,
|
||||
&cnt, &len, &data->bios);
|
||||
if (!ram->base.rammap.data || ram->base.rammap.version != 0x11 ||
|
||||
ram->base.rammap.size < 0x09) {
|
||||
nv_error(pfb, "invalid/missing rammap entry\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* locate specific data set for the attached memory */
|
||||
strap = nvbios_ramcfg_index(nv_subdev(pfb));
|
||||
ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data,
|
||||
ram->base.rammap.version,
|
||||
ram->base.rammap.size,
|
||||
cnt, len, strap,
|
||||
&ram->base.ramcfg.version,
|
||||
&ram->base.ramcfg.size,
|
||||
&data->bios);
|
||||
if (!ram->base.ramcfg.data || ram->base.ramcfg.version != 0x11 ||
|
||||
ram->base.ramcfg.size < 0x08) {
|
||||
nv_error(pfb, "invalid/missing ramcfg entry\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* lookup memory timings, if bios says they're present */
|
||||
strap = nv_ro08(bios, ram->base.ramcfg.data + 0x00);
|
||||
if (strap != 0xff) {
|
||||
ram->base.timing.data =
|
||||
nvbios_timingEp(bios, strap, &ram->base.timing.version,
|
||||
&ram->base.timing.size, &cnt, &len,
|
||||
&data->bios);
|
||||
if (!ram->base.timing.data ||
|
||||
ram->base.timing.version != 0x20 ||
|
||||
ram->base.timing.size < 0x33) {
|
||||
nv_error(pfb, "invalid/missing timing entry\n");
|
||||
return -EINVAL;
|
||||
list_for_each_entry(cfg, &ram->cfg, head) {
|
||||
if (mhz >= cfg->bios.rammap_min &&
|
||||
mhz <= cfg->bios.rammap_max) {
|
||||
*data = *cfg;
|
||||
data->freq = khz;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
ram->base.timing.data = 0;
|
||||
}
|
||||
|
||||
data->freq = freq;
|
||||
return 0;
|
||||
nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1106,13 +1072,99 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
|
||||
return nve0_ram_calc_xits(pfb, ram->base.next);
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_ram_prog_0(struct nouveau_fb *pfb, u32 freq)
|
||||
{
|
||||
struct nve0_ram *ram = (void *)pfb->ram;
|
||||
struct nouveau_ram_data *cfg;
|
||||
u32 mhz = freq / 1000;
|
||||
u32 mask, data;
|
||||
|
||||
list_for_each_entry(cfg, &ram->cfg, head) {
|
||||
if (mhz >= cfg->bios.rammap_min &&
|
||||
mhz <= cfg->bios.rammap_max)
|
||||
break;
|
||||
}
|
||||
|
||||
if (&cfg->head == &ram->cfg)
|
||||
return;
|
||||
|
||||
if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) {
|
||||
data |= cfg->bios.rammap_11_0a_03fe << 12;
|
||||
mask |= 0x001ff000;
|
||||
}
|
||||
if (ram->diff.rammap_11_09_01ff) {
|
||||
data |= cfg->bios.rammap_11_09_01ff;
|
||||
mask |= 0x000001ff;
|
||||
}
|
||||
nv_mask(pfb, 0x10f468, mask, data);
|
||||
|
||||
if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) {
|
||||
data |= cfg->bios.rammap_11_0a_0400;
|
||||
mask |= 0x00000001;
|
||||
}
|
||||
nv_mask(pfb, 0x10f420, mask, data);
|
||||
|
||||
if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) {
|
||||
data |= cfg->bios.rammap_11_0a_0800;
|
||||
mask |= 0x00000001;
|
||||
}
|
||||
nv_mask(pfb, 0x10f430, mask, data);
|
||||
|
||||
if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) {
|
||||
data |= cfg->bios.rammap_11_0b_01f0;
|
||||
mask |= 0x0000001f;
|
||||
}
|
||||
nv_mask(pfb, 0x10f400, mask, data);
|
||||
|
||||
if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) {
|
||||
data |= cfg->bios.rammap_11_0b_0200 << 9;
|
||||
mask |= 0x00000200;
|
||||
}
|
||||
nv_mask(pfb, 0x10f410, mask, data);
|
||||
|
||||
if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
|
||||
data |= cfg->bios.rammap_11_0d << 16;
|
||||
mask |= 0x00ff0000;
|
||||
}
|
||||
if (ram->diff.rammap_11_0f) {
|
||||
data |= cfg->bios.rammap_11_0f << 8;
|
||||
mask |= 0x0000ff00;
|
||||
}
|
||||
nv_mask(pfb, 0x10f440, mask, data);
|
||||
|
||||
if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
|
||||
data |= cfg->bios.rammap_11_0e << 8;
|
||||
mask |= 0x0000ff00;
|
||||
}
|
||||
if (ram->diff.rammap_11_0b_0800) {
|
||||
data |= cfg->bios.rammap_11_0b_0800 << 7;
|
||||
mask |= 0x00000080;
|
||||
}
|
||||
if (ram->diff.rammap_11_0b_0400) {
|
||||
data |= cfg->bios.rammap_11_0b_0400 << 5;
|
||||
mask |= 0x00000020;
|
||||
}
|
||||
nv_mask(pfb, 0x10f444, mask, data);
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_ram_prog(struct nouveau_fb *pfb)
|
||||
{
|
||||
struct nouveau_device *device = nv_device(pfb);
|
||||
struct nve0_ram *ram = (void *)pfb->ram;
|
||||
struct nve0_ramfuc *fuc = &ram->fuc;
|
||||
ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
|
||||
struct nouveau_ram_data *next = ram->base.next;
|
||||
|
||||
if (!nouveau_boolopt(device->cfgopt, "NvMemExec", true)) {
|
||||
ram_exec(fuc, false);
|
||||
return (ram->base.next == &ram->base.xition);
|
||||
}
|
||||
|
||||
nve0_ram_prog_0(pfb, 1000);
|
||||
ram_exec(fuc, true);
|
||||
nve0_ram_prog_0(pfb, next->freq);
|
||||
|
||||
return (ram->base.next == &ram->base.xition);
|
||||
}
|
||||
|
||||
@ -1125,24 +1177,147 @@ nve0_ram_tidy(struct nouveau_fb *pfb)
|
||||
ram_exec(fuc, false);
|
||||
}
|
||||
|
||||
struct nve0_ram_train {
|
||||
u16 mask;
|
||||
struct nvbios_M0209S remap;
|
||||
struct nvbios_M0209S type00;
|
||||
struct nvbios_M0209S type01;
|
||||
struct nvbios_M0209S type04;
|
||||
struct nvbios_M0209S type06;
|
||||
struct nvbios_M0209S type07;
|
||||
struct nvbios_M0209S type08;
|
||||
struct nvbios_M0209S type09;
|
||||
};
|
||||
|
||||
static int
|
||||
nve0_ram_train_type(struct nouveau_fb *pfb, int i, u8 ramcfg,
|
||||
struct nve0_ram_train *train)
|
||||
{
|
||||
struct nouveau_bios *bios = nouveau_bios(pfb);
|
||||
struct nvbios_M0205E M0205E;
|
||||
struct nvbios_M0205S M0205S;
|
||||
struct nvbios_M0209E M0209E;
|
||||
struct nvbios_M0209S *remap = &train->remap;
|
||||
struct nvbios_M0209S *value;
|
||||
u8 ver, hdr, cnt, len;
|
||||
u32 data;
|
||||
|
||||
/* determine type of data for this index */
|
||||
if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)))
|
||||
return -ENOENT;
|
||||
|
||||
switch (M0205E.type) {
|
||||
case 0x00: value = &train->type00; break;
|
||||
case 0x01: value = &train->type01; break;
|
||||
case 0x04: value = &train->type04; break;
|
||||
case 0x06: value = &train->type06; break;
|
||||
case 0x07: value = &train->type07; break;
|
||||
case 0x08: value = &train->type08; break;
|
||||
case 0x09: value = &train->type09; break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* training data index determined by ramcfg strap */
|
||||
if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S)))
|
||||
return -EINVAL;
|
||||
i = M0205S.data;
|
||||
|
||||
/* training data format information */
|
||||
if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E)))
|
||||
return -EINVAL;
|
||||
|
||||
/* ... and the raw data */
|
||||
if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value)))
|
||||
return -EINVAL;
|
||||
|
||||
if (M0209E.v02_07 == 2) {
|
||||
/* of course! why wouldn't we have a pointer to another entry
|
||||
* in the same table, and use the first one as an array of
|
||||
* remap indices...
|
||||
*/
|
||||
if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr,
|
||||
remap)))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(value->data); i++)
|
||||
value->data[i] = remap->data[value->data[i]];
|
||||
} else
|
||||
if (M0209E.v02_07 != 1)
|
||||
return -EINVAL;
|
||||
|
||||
train->mask |= 1 << M0205E.type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_ram_train_init_0(struct nouveau_fb *pfb, struct nve0_ram_train *train)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if ((train->mask & 0x03d3) != 0x03d3) {
|
||||
nv_warn(pfb, "missing link training data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 0x30; i++) {
|
||||
for (j = 0; j < 8; j += 4) {
|
||||
nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8));
|
||||
nv_wr32(pfb, 0x10f920 + j, 0x00000000 |
|
||||
train->type08.data[i] << 4 |
|
||||
train->type06.data[i]);
|
||||
nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]);
|
||||
nv_wr32(pfb, 0x10f920 + j, 0x00000100 |
|
||||
train->type09.data[i] << 4 |
|
||||
train->type07.data[i]);
|
||||
nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j += 4) {
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
nv_wr32(pfb, 0x10f968 + j, i);
|
||||
nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nve0_ram_train_init(struct nouveau_fb *pfb)
|
||||
{
|
||||
u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
|
||||
struct nve0_ram_train *train;
|
||||
int ret = -ENOMEM, i;
|
||||
|
||||
if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) {
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
ret = nve0_ram_train_type(pfb, i, ramcfg, train);
|
||||
if (ret && ret != -ENOENT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (pfb->ram->type) {
|
||||
case NV_MEM_TYPE_GDDR5:
|
||||
ret = nve0_ram_train_init_0(pfb, train);
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(train);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
nve0_ram_init(struct nouveau_object *object)
|
||||
{
|
||||
struct nouveau_fb *pfb = (void *)object->parent;
|
||||
struct nve0_ram *ram = (void *)object;
|
||||
struct nouveau_bios *bios = nouveau_bios(pfb);
|
||||
static const u8 train0[] = {
|
||||
0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
|
||||
0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
|
||||
};
|
||||
static const u32 train1[] = {
|
||||
0x00000000, 0xffffffff,
|
||||
0x55555555, 0xaaaaaaaa,
|
||||
0x33333333, 0xcccccccc,
|
||||
0xf0f0f0f0, 0x0f0f0f0f,
|
||||
0x00ff00ff, 0xff00ff00,
|
||||
0x0000ffff, 0xffff0000,
|
||||
};
|
||||
u8 ver, hdr, cnt, len, snr, ssz;
|
||||
u32 data, save;
|
||||
int ret, i;
|
||||
@ -1168,51 +1343,107 @@ nve0_ram_init(struct nouveau_object *object)
|
||||
|
||||
cnt = nv_ro08(bios, data + 0x14); /* guess at count */
|
||||
data = nv_ro32(bios, data + 0x10); /* guess u32... */
|
||||
save = nv_rd32(pfb, 0x10f65c);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
|
||||
nvbios_exec(&(struct nvbios_init) {
|
||||
.subdev = nv_subdev(pfb),
|
||||
.bios = bios,
|
||||
.offset = nv_ro32(bios, data), /* guess u32 */
|
||||
.execute = 1,
|
||||
});
|
||||
data += 4;
|
||||
save = nv_rd32(pfb, 0x10f65c) & 0x000000f0;
|
||||
for (i = 0; i < cnt; i++, data += 4) {
|
||||
if (i != save >> 4) {
|
||||
nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
|
||||
nvbios_exec(&(struct nvbios_init) {
|
||||
.subdev = nv_subdev(pfb),
|
||||
.bios = bios,
|
||||
.offset = nv_ro32(bios, data),
|
||||
.execute = 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
nv_wr32(pfb, 0x10f65c, save);
|
||||
nv_mask(pfb, 0x10f65c, 0x000000f0, save);
|
||||
nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
|
||||
nv_wr32(pfb, 0x10ecc0, 0xffffffff);
|
||||
nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010);
|
||||
|
||||
switch (ram->base.type) {
|
||||
case NV_MEM_TYPE_GDDR5:
|
||||
for (i = 0; i < 0x30; i++) {
|
||||
nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
|
||||
nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
|
||||
nv_wr32(pfb, 0x10f918, train1[i % 12]);
|
||||
nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
|
||||
nv_wr32(pfb, 0x10f918, train1[i % 12]);
|
||||
return nve0_ram_train_init(pfb);
|
||||
}
|
||||
|
||||
nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
|
||||
nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
|
||||
nv_wr32(pfb, 0x10f91c, train1[i % 12]);
|
||||
nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
|
||||
nv_wr32(pfb, 0x10f91c, train1[i % 12]);
|
||||
}
|
||||
static int
|
||||
nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i)
|
||||
{
|
||||
struct nouveau_fb *pfb = (void *)nv_object(ram)->parent;
|
||||
struct nouveau_bios *bios = nouveau_bios(pfb);
|
||||
struct nouveau_ram_data *cfg;
|
||||
struct nvbios_ramcfg *d = &ram->diff;
|
||||
struct nvbios_ramcfg *p, *n;
|
||||
u8 ver, hdr, cnt, len;
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
nv_wr32(pfb, 0x10f968, i);
|
||||
nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]);
|
||||
}
|
||||
if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios;
|
||||
n = &cfg->bios;
|
||||
|
||||
for (i = 0; i < 0x100; i++) {
|
||||
nv_wr32(pfb, 0x10f96c, i);
|
||||
nv_wr32(pfb, 0x10f900, train1[2 + (i & 1)]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
/* memory config data for a range of target frequencies */
|
||||
data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
|
||||
if (ret = -ENOENT, !data)
|
||||
goto done;
|
||||
if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
|
||||
goto done;
|
||||
|
||||
/* ... and a portion specific to the attached memory */
|
||||
data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
|
||||
&ver, &hdr, &cfg->bios);
|
||||
if (ret = -EINVAL, !data)
|
||||
goto done;
|
||||
if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
|
||||
goto done;
|
||||
|
||||
/* lookup memory timings, if bios says they're present */
|
||||
if (cfg->bios.ramcfg_timing != 0xff) {
|
||||
data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
|
||||
&ver, &hdr, &cnt, &len,
|
||||
&cfg->bios);
|
||||
if (ret = -EINVAL, !data)
|
||||
goto done;
|
||||
if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
|
||||
goto done;
|
||||
}
|
||||
|
||||
return 0;
|
||||
list_add_tail(&cfg->head, &ram->cfg);
|
||||
if (ret = 0, i == 0)
|
||||
goto done;
|
||||
|
||||
d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe;
|
||||
d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff;
|
||||
d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400;
|
||||
d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800;
|
||||
d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0;
|
||||
d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200;
|
||||
d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d;
|
||||
d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f;
|
||||
d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e;
|
||||
d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800;
|
||||
d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400;
|
||||
d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01;
|
||||
d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02;
|
||||
d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10;
|
||||
d->ramcfg_11_02_03 |= p->ramcfg_11_02_03 != n->ramcfg_11_02_03;
|
||||
d->ramcfg_11_08_20 |= p->ramcfg_11_08_20 != n->ramcfg_11_08_20;
|
||||
d->timing_20_30_07 |= p->timing_20_30_07 != n->timing_20_30_07;
|
||||
done:
|
||||
if (ret)
|
||||
kfree(cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nve0_ram_dtor(struct nouveau_object *object)
|
||||
{
|
||||
struct nve0_ram *ram = (void *)object;
|
||||
struct nouveau_ram_data *cfg, *tmp;
|
||||
|
||||
list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
|
||||
kfree(cfg);
|
||||
}
|
||||
|
||||
nouveau_ram_destroy(&ram->base);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1226,6 +1457,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
struct dcb_gpio_func func;
|
||||
struct nve0_ram *ram;
|
||||
int ret, i;
|
||||
u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
|
||||
u32 tmp;
|
||||
|
||||
ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
|
||||
@ -1233,6 +1465,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
INIT_LIST_HEAD(&ram->cfg);
|
||||
|
||||
switch (ram->base.type) {
|
||||
case NV_MEM_TYPE_DDR3:
|
||||
case NV_MEM_TYPE_GDDR5:
|
||||
@ -1264,7 +1498,26 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
}
|
||||
}
|
||||
|
||||
// parse bios data for both pll's
|
||||
/* parse bios data for all rammap table entries up-front, and
|
||||
* build information on whether certain fields differ between
|
||||
* any of the entries.
|
||||
*
|
||||
* the binary driver appears to completely ignore some fields
|
||||
* when all entries contain the same value. at first, it was
|
||||
* hoped that these were mere optimisations and the bios init
|
||||
* tables had configured as per the values here, but there is
|
||||
* evidence now to suggest that this isn't the case and we do
|
||||
* need to treat this condition as a "don't touch" indicator.
|
||||
*/
|
||||
for (i = 0; !ret; i++) {
|
||||
ret = nve0_ram_ctor_data(ram, ramcfg, i);
|
||||
if (ret && ret != -ENOENT) {
|
||||
nv_error(pfb, "failed to parse ramcfg data\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse bios data for both pll's */
|
||||
ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
|
||||
if (ret) {
|
||||
nv_error(pfb, "mclk refpll data not found\n");
|
||||
@ -1277,6 +1530,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* lookup memory voltage gpios */
|
||||
ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
|
||||
if (ret == 0) {
|
||||
ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
|
||||
@ -1385,7 +1639,7 @@ nve0_ram_oclass = {
|
||||
.handle = 0,
|
||||
.ofuncs = &(struct nouveau_ofuncs) {
|
||||
.ctor = nve0_ram_ctor,
|
||||
.dtor = _nouveau_ram_dtor,
|
||||
.dtor = nve0_ram_dtor,
|
||||
.init = nve0_ram_init,
|
||||
.fini = _nouveau_ram_fini,
|
||||
}
|
||||
|
94
drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
Normal file
94
drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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);
|
||||
CL = ramxlat(ramddr3_cl, CL);
|
||||
WR = ramxlat(ramddr3_wr, WR);
|
||||
if (WL < 0 || CL < 0 || WR < 0)
|
||||
CWL = ramxlat(ramddr3_cwl, CWL);
|
||||
CL = ramxlat(ramddr3_cl, CL);
|
||||
WR = ramxlat(ramddr3_wr, WR);
|
||||
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;
|
||||
}
|
||||
|
54
drivers/gpu/drm/nouveau/core/subdev/fuse/base.c
Normal file
54
drivers/gpu/drm/nouveau/core/subdev/fuse/base.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
81
drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c
Normal file
81
drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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,
|
||||
},
|
||||
};
|
83
drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c
Normal file
83
drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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,
|
||||
},
|
||||
};
|
66
drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c
Normal file
66
drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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,
|
||||
},
|
||||
};
|
9
drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h
Normal file
9
drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h
Normal file
@ -0,0 +1,9 @@
|
||||
#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);
|
||||
|
94
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc
Normal file
94
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
|
||||
// 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,10 +366,10 @@ timer:
|
||||
cmp b32 $r14 $r0
|
||||
bra e #timer_reset
|
||||
cmp b32 $r14 $r8
|
||||
bra l #timer_done
|
||||
timer_reset:
|
||||
nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
|
||||
st b32 D[$r0 + #time_prev] $r14
|
||||
bra g #timer_enable
|
||||
timer_reset:
|
||||
nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
|
||||
st b32 D[$r0 + #time_prev] $r14
|
||||
|
||||
// re-enable the watchdog timer
|
||||
timer_enable:
|
||||
@ -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
|
||||
|
@ -43,17 +43,23 @@ process(PROC_MEMX, #memx_init, #memx_recv)
|
||||
*/ .b32 func
|
||||
|
||||
memx_func_head:
|
||||
handler(ENTER , 0x0001, 0x0000, #memx_func_enter)
|
||||
handler(ENTER , 0x0000, 0x0000, #memx_func_enter)
|
||||
memx_func_next:
|
||||
handler(LEAVE , 0x0000, 0x0000, #memx_func_leave)
|
||||
handler(WR32 , 0x0000, 0x0002, #memx_func_wr32)
|
||||
handler(WAIT , 0x0004, 0x0000, #memx_func_wait)
|
||||
handler(DELAY , 0x0001, 0x0000, #memx_func_delay)
|
||||
handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank)
|
||||
memx_func_tail:
|
||||
|
||||
.equ #memx_func_size #memx_func_next - #memx_func_head
|
||||
.equ #memx_func_num (#memx_func_tail - #memx_func_head) / #memx_func_size
|
||||
|
||||
memx_ts_start:
|
||||
.b32 0
|
||||
memx_ts_end:
|
||||
.b32 0
|
||||
|
||||
memx_data_head:
|
||||
.skip 0x0800
|
||||
memx_data_tail:
|
||||
@ -67,19 +73,44 @@ memx_data_tail:
|
||||
//
|
||||
// $r15 - current (memx)
|
||||
// $r4 - packet length
|
||||
// +00: bitmask of heads to wait for vblank on
|
||||
// $r3 - opcode desciption
|
||||
// $r0 - zero
|
||||
memx_func_enter:
|
||||
#if NVKM_PPWR_CHIPSET == GT215
|
||||
movw $r8 0x1610
|
||||
nv_rd32($r7, $r8)
|
||||
imm32($r6, 0xfffffffc)
|
||||
and $r7 $r6
|
||||
movw $r6 0x2
|
||||
or $r7 $r6
|
||||
nv_wr32($r8, $r7)
|
||||
#else
|
||||
movw $r6 0x001620
|
||||
imm32($r7, ~0x00000aa2);
|
||||
nv_rd32($r8, $r6)
|
||||
and $r8 $r7
|
||||
nv_wr32($r6, $r8)
|
||||
|
||||
imm32($r7, ~0x00000001)
|
||||
nv_rd32($r8, $r6)
|
||||
and $r8 $r7
|
||||
nv_wr32($r6, $r8)
|
||||
|
||||
movw $r6 0x0026f0
|
||||
nv_rd32($r8, $r6)
|
||||
and $r8 $r7
|
||||
nv_wr32($r6, $r8)
|
||||
#endif
|
||||
|
||||
mov $r6 NV_PPWR_OUTPUT_SET_FB_PAUSE
|
||||
nv_iowr(NV_PPWR_OUTPUT_SET, $r6)
|
||||
memx_func_enter_wait:
|
||||
nv_iord($r6, NV_PPWR_OUTPUT)
|
||||
and $r6 NV_PPWR_OUTPUT_FB_PAUSE
|
||||
bra z #memx_func_enter_wait
|
||||
//XXX: TODO
|
||||
ld b32 $r6 D[$r1 + 0x00]
|
||||
add b32 $r1 0x04
|
||||
|
||||
nv_iord($r6, NV_PPWR_TIMER_LOW)
|
||||
st b32 D[$r0 + #memx_ts_start] $r6
|
||||
ret
|
||||
|
||||
// description
|
||||
@ -89,14 +120,93 @@ memx_func_enter:
|
||||
// $r3 - opcode desciption
|
||||
// $r0 - zero
|
||||
memx_func_leave:
|
||||
nv_iord($r6, NV_PPWR_TIMER_LOW)
|
||||
st b32 D[$r0 + #memx_ts_end] $r6
|
||||
|
||||
mov $r6 NV_PPWR_OUTPUT_CLR_FB_PAUSE
|
||||
nv_iowr(NV_PPWR_OUTPUT_CLR, $r6)
|
||||
memx_func_leave_wait:
|
||||
nv_iord($r6, NV_PPWR_OUTPUT)
|
||||
and $r6 NV_PPWR_OUTPUT_FB_PAUSE
|
||||
bra nz #memx_func_leave_wait
|
||||
|
||||
#if NVKM_PPWR_CHIPSET == GT215
|
||||
movw $r8 0x1610
|
||||
nv_rd32($r7, $r8)
|
||||
imm32($r6, 0xffffffcc)
|
||||
and $r7 $r6
|
||||
nv_wr32($r8, $r7)
|
||||
#else
|
||||
movw $r6 0x0026f0
|
||||
imm32($r7, 0x00000001)
|
||||
nv_rd32($r8, $r6)
|
||||
or $r8 $r7
|
||||
nv_wr32($r6, $r8)
|
||||
|
||||
movw $r6 0x001620
|
||||
nv_rd32($r8, $r6)
|
||||
or $r8 $r7
|
||||
nv_wr32($r6, $r8)
|
||||
|
||||
imm32($r7, 0x00000aa2);
|
||||
nv_rd32($r8, $r6)
|
||||
or $r8 $r7
|
||||
nv_wr32($r6, $r8)
|
||||
#endif
|
||||
ret
|
||||
|
||||
#if NVKM_PPWR_CHIPSET < GF119
|
||||
// description
|
||||
//
|
||||
// $r15 - current (memx)
|
||||
// $r4 - packet length
|
||||
// +00: head to wait for vblank on
|
||||
// $r3 - opcode desciption
|
||||
// $r0 - zero
|
||||
memx_func_wait_vblank:
|
||||
ld b32 $r6 D[$r1 + 0x00]
|
||||
cmp b32 $r6 0x0
|
||||
bra z #memx_func_wait_vblank_head0
|
||||
cmp b32 $r6 0x1
|
||||
bra z #memx_func_wait_vblank_head1
|
||||
bra #memx_func_wait_vblank_fini
|
||||
|
||||
memx_func_wait_vblank_head1:
|
||||
movw $r7 0x20
|
||||
bra #memx_func_wait_vblank_0
|
||||
|
||||
memx_func_wait_vblank_head0:
|
||||
movw $r7 0x8
|
||||
|
||||
memx_func_wait_vblank_0:
|
||||
nv_iord($r6, NV_PPWR_INPUT)
|
||||
and $r6 $r7
|
||||
bra nz #memx_func_wait_vblank_0
|
||||
|
||||
memx_func_wait_vblank_1:
|
||||
nv_iord($r6, NV_PPWR_INPUT)
|
||||
and $r6 $r7
|
||||
bra z #memx_func_wait_vblank_1
|
||||
|
||||
memx_func_wait_vblank_fini:
|
||||
add b32 $r1 0x4
|
||||
ret
|
||||
|
||||
#else
|
||||
|
||||
// XXX: currently no-op
|
||||
//
|
||||
// $r15 - current (memx)
|
||||
// $r4 - packet length
|
||||
// +00: head to wait for vblank on
|
||||
// $r3 - opcode desciption
|
||||
// $r0 - zero
|
||||
memx_func_wait_vblank:
|
||||
add b32 $r1 0x4
|
||||
ret
|
||||
|
||||
#endif
|
||||
|
||||
// description
|
||||
//
|
||||
// $r15 - current (memx)
|
||||
@ -160,14 +270,17 @@ memx_exec:
|
||||
push $r13
|
||||
mov b32 $r1 $r12
|
||||
mov b32 $r2 $r11
|
||||
|
||||
memx_exec_next:
|
||||
// fetch the packet header, and locate opcode info
|
||||
// fetch the packet header
|
||||
ld b32 $r3 D[$r1]
|
||||
add b32 $r1 4
|
||||
shr b32 $r4 $r3 16
|
||||
mulu $r3 #memx_func_size
|
||||
extr $r4 $r3 16:31
|
||||
extr $r3 $r3 0:15
|
||||
|
||||
// execute the opcode handler
|
||||
sub b32 $r3 1
|
||||
mulu $r3 #memx_func_size
|
||||
ld b32 $r5 D[$r3 + #memx_func_head + #memx_func]
|
||||
call $r5
|
||||
|
||||
@ -176,6 +289,10 @@ memx_exec:
|
||||
bra l #memx_exec_next
|
||||
|
||||
// send completion reply
|
||||
ld b32 $r11 D[$r0 + #memx_ts_start]
|
||||
ld b32 $r12 D[$r0 + #memx_ts_end]
|
||||
sub b32 $r12 $r11
|
||||
nv_iord($r11, NV_PPWR_INPUT)
|
||||
pop $r13
|
||||
pop $r14
|
||||
call(send)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user