Commit 0411de85 authored by Ben Skeggs's avatar Ben Skeggs

drm/nvc0/gr: import and use our own fuc by default

The ability to use NVIDIA's fuc has been retained *temporarily* in order
to better debug any issues that may be lingering in our initial attempt
at writing this ucode.  Once I'm fairly confident we're okay, it'll be
removed.

There's a number of things not implemented by this fuc currently, but
most of it is sets of state that our context setup would not have used
anyway.  No doubt we'll find out what they're for at some point, and
implement it if required.

This has been tested on 0xc0/0xc4 thus far, and from what I could tell
it worked as well as NVIDIA's.  It's also been tested on 0xc1, but even
with NVIDIA's fuc that chipset doesn't work correctly with nouveau yet.

0xc3/0xc8/0xce should in theory be supported too, but I don't have the
hardware to check that.

There's no doubt numerous bugs to squash yet, please report any!
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent f8522fc8
...@@ -119,6 +119,10 @@ MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n"); ...@@ -119,6 +119,10 @@ MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n");
int nouveau_msi; int nouveau_msi;
module_param_named(msi, nouveau_msi, int, 0400); module_param_named(msi, nouveau_msi, int, 0400);
MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)\n");
int nouveau_ctxfw;
module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
int nouveau_fbpercrtc; int nouveau_fbpercrtc;
#if 0 #if 0
module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400); module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
......
...@@ -786,6 +786,7 @@ extern int nouveau_override_conntype; ...@@ -786,6 +786,7 @@ extern int nouveau_override_conntype;
extern char *nouveau_perflvl; extern char *nouveau_perflvl;
extern int nouveau_perflvl_wr; extern int nouveau_perflvl_wr;
extern int nouveau_msi; extern int nouveau_msi;
extern int nouveau_ctxfw;
extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
extern int nouveau_pci_resume(struct pci_dev *pdev); extern int nouveau_pci_resume(struct pci_dev *pdev);
......
...@@ -28,7 +28,34 @@ ...@@ -28,7 +28,34 @@
#include "nouveau_drv.h" #include "nouveau_drv.h"
#include "nouveau_mm.h" #include "nouveau_mm.h"
#include "nvc0_graph.h" #include "nvc0_graph.h"
#include "nvc0_grhub.fuc.h"
#include "nvc0_grgpc.fuc.h"
static void
nvc0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
{
NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
nv_rd32(dev, base + 0x400));
NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
}
static void
nvc0_graph_ctxctl_debug(struct drm_device *dev)
{
u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
u32 gpc;
nvc0_graph_ctxctl_debug_unit(dev, 0x409000);
for (gpc = 0; gpc < gpcnr; gpc++)
nvc0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
}
static int static int
nvc0_graph_load_context(struct nouveau_channel *chan) nvc0_graph_load_context(struct nouveau_channel *chan)
...@@ -72,6 +99,16 @@ nvc0_graph_construct_context(struct nouveau_channel *chan) ...@@ -72,6 +99,16 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
if (!nouveau_ctxfw) {
nv_wr32(dev, 0x409840, 0x80000000);
nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
nv_wr32(dev, 0x409504, 0x00000001);
if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
NV_ERROR(dev, "PGRAPH: HUB_SET_CHAN timeout\n");
nvc0_graph_ctxctl_debug(dev);
return -EBUSY;
}
} else {
nvc0_graph_load_context(chan); nvc0_graph_load_context(chan);
nv_wo32(grch->grctx, 0x1c, 1); nv_wo32(grch->grctx, 0x1c, 1);
...@@ -79,6 +116,7 @@ nvc0_graph_construct_context(struct nouveau_channel *chan) ...@@ -79,6 +116,7 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
nv_wo32(grch->grctx, 0x28, 0); nv_wo32(grch->grctx, 0x28, 0);
nv_wo32(grch->grctx, 0x2c, 0); nv_wo32(grch->grctx, 0x2c, 0);
dev_priv->engine.instmem.flush(dev); dev_priv->engine.instmem.flush(dev);
}
ret = nvc0_grctx_generate(chan); ret = nvc0_grctx_generate(chan);
if (ret) { if (ret) {
...@@ -86,11 +124,22 @@ nvc0_graph_construct_context(struct nouveau_channel *chan) ...@@ -86,11 +124,22 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
return ret; return ret;
} }
if (!nouveau_ctxfw) {
nv_wr32(dev, 0x409840, 0x80000000);
nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
nv_wr32(dev, 0x409504, 0x00000002);
if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
NV_ERROR(dev, "PGRAPH: HUB_CTX_SAVE timeout\n");
nvc0_graph_ctxctl_debug(dev);
return -EBUSY;
}
} else {
ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst); ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst);
if (ret) { if (ret) {
kfree(ctx); kfree(ctx);
return ret; return ret;
} }
}
for (i = 0; i < priv->grctx_size; i += 4) for (i = 0; i < priv->grctx_size; i += 4)
ctx[i / 4] = nv_ro32(grch->grctx, i); ctx[i / 4] = nv_ro32(grch->grctx, i);
...@@ -210,6 +259,10 @@ nvc0_graph_context_new(struct nouveau_channel *chan, int engine) ...@@ -210,6 +259,10 @@ nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
for (i = 0; i < priv->grctx_size; i += 4) for (i = 0; i < priv->grctx_size; i += 4)
nv_wo32(grctx, i, priv->grctx_vals[i / 4]); nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
if (!nouveau_ctxfw) {
nv_wo32(grctx, 0x00, grch->mmio_nr);
nv_wo32(grctx, 0x04, grch->mmio->linst >> 8);
} else {
nv_wo32(grctx, 0xf4, 0); nv_wo32(grctx, 0xf4, 0);
nv_wo32(grctx, 0xf8, 0); nv_wo32(grctx, 0xf8, 0);
nv_wo32(grctx, 0x10, grch->mmio_nr); nv_wo32(grctx, 0x10, grch->mmio_nr);
...@@ -219,6 +272,7 @@ nvc0_graph_context_new(struct nouveau_channel *chan, int engine) ...@@ -219,6 +272,7 @@ nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
nv_wo32(grctx, 0x20, 0); nv_wo32(grctx, 0x20, 0);
nv_wo32(grctx, 0x28, 0); nv_wo32(grctx, 0x28, 0);
nv_wo32(grctx, 0x2c, 0); nv_wo32(grctx, 0x2c, 0);
}
pinstmem->flush(dev); pinstmem->flush(dev);
return 0; return 0;
...@@ -419,8 +473,51 @@ nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base, ...@@ -419,8 +473,51 @@ nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
static int static int
nvc0_graph_init_ctxctl(struct drm_device *dev) nvc0_graph_init_ctxctl(struct drm_device *dev)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
u32 r000260; u32 r000260;
int i;
if (!nouveau_ctxfw) {
/* load HUB microcode */
r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
nv_wr32(dev, 0x4091c0, 0x01000000);
for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++)
nv_wr32(dev, 0x4091c4, nvc0_grhub_data[i]);
nv_wr32(dev, 0x409180, 0x01000000);
for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(dev, 0x409188, i >> 6);
nv_wr32(dev, 0x409184, nvc0_grhub_code[i]);
}
/* load GPC microcode */
nv_wr32(dev, 0x41a1c0, 0x01000000);
for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++)
nv_wr32(dev, 0x41a1c4, nvc0_grgpc_data[i]);
nv_wr32(dev, 0x41a180, 0x01000000);
for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(dev, 0x41a188, i >> 6);
nv_wr32(dev, 0x41a184, nvc0_grgpc_code[i]);
}
nv_wr32(dev, 0x000260, r000260);
/* start HUB ucode running, it'll init the GPCs */
nv_wr32(dev, 0x409800, dev_priv->chipset);
nv_wr32(dev, 0x40910c, 0x00000000);
nv_wr32(dev, 0x409100, 0x00000002);
if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
NV_ERROR(dev, "PGRAPH: HUB_INIT timed out\n");
nvc0_graph_ctxctl_debug(dev);
return -EBUSY;
}
priv->grctx_size = nv_rd32(dev, 0x409804);
return 0;
}
/* load fuc microcode */ /* load fuc microcode */
r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
...@@ -527,6 +624,22 @@ nvc0_graph_isr_chid(struct drm_device *dev, u64 inst) ...@@ -527,6 +624,22 @@ nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
return i; return i;
} }
static void
nvc0_graph_ctxctl_isr(struct drm_device *dev)
{
u32 ustat = nv_rd32(dev, 0x409c18);
if (ustat & 0x00000001)
NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
if (ustat & 0x00080000)
NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
if (ustat & ~0x00080001)
NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
nvc0_graph_ctxctl_debug(dev);
nv_wr32(dev, 0x409c20, ustat);
}
static void static void
nvc0_graph_isr(struct drm_device *dev) nvc0_graph_isr(struct drm_device *dev)
{ {
...@@ -578,11 +691,7 @@ nvc0_graph_isr(struct drm_device *dev) ...@@ -578,11 +691,7 @@ nvc0_graph_isr(struct drm_device *dev)
} }
if (stat & 0x00080000) { if (stat & 0x00080000) {
u32 ustat = nv_rd32(dev, 0x409c18); nvc0_graph_ctxctl_isr(dev);
NV_INFO(dev, "PGRAPH: CTXCTRL ustat 0x%08x\n", ustat);
nv_wr32(dev, 0x409c20, ustat);
nv_wr32(dev, 0x400100, 0x00080000); nv_wr32(dev, 0x400100, 0x00080000);
stat &= ~0x00080000; stat &= ~0x00080000;
} }
...@@ -651,10 +760,12 @@ nvc0_graph_destroy(struct drm_device *dev, int engine) ...@@ -651,10 +760,12 @@ nvc0_graph_destroy(struct drm_device *dev, int engine)
{ {
struct nvc0_graph_priv *priv = nv_engine(dev, engine); struct nvc0_graph_priv *priv = nv_engine(dev, engine);
if (nouveau_ctxfw) {
nvc0_graph_destroy_fw(&priv->fuc409c); nvc0_graph_destroy_fw(&priv->fuc409c);
nvc0_graph_destroy_fw(&priv->fuc409d); nvc0_graph_destroy_fw(&priv->fuc409d);
nvc0_graph_destroy_fw(&priv->fuc41ac); nvc0_graph_destroy_fw(&priv->fuc41ac);
nvc0_graph_destroy_fw(&priv->fuc41ad); nvc0_graph_destroy_fw(&priv->fuc41ad);
}
nouveau_irq_unregister(dev, 12); nouveau_irq_unregister(dev, 12);
nouveau_irq_unregister(dev, 25); nouveau_irq_unregister(dev, 25);
...@@ -698,6 +809,8 @@ nvc0_graph_create(struct drm_device *dev) ...@@ -698,6 +809,8 @@ nvc0_graph_create(struct drm_device *dev)
nouveau_irq_register(dev, 12, nvc0_graph_isr); nouveau_irq_register(dev, 12, nvc0_graph_isr);
nouveau_irq_register(dev, 25, nvc0_runk140_isr); nouveau_irq_register(dev, 25, nvc0_runk140_isr);
if (nouveau_ctxfw) {
NV_INFO(dev, "PGRAPH: using external firmware\n");
if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) || if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) || nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) || nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
...@@ -705,7 +818,7 @@ nvc0_graph_create(struct drm_device *dev) ...@@ -705,7 +818,7 @@ nvc0_graph_create(struct drm_device *dev)
ret = 0; ret = 0;
goto error; goto error;
} }
}
ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
if (ret) if (ret)
......
/* fuc microcode util functions for nvc0 PGRAPH
*
* Copyright 2011 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
*/
define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
ifdef(`include_code', `
// Error codes
define(`E_BAD_COMMAND', 0x01)
define(`E_CMD_OVERFLOW', 0x02)
// Util macros to help with debugging ucode hangs etc
define(`T_WAIT', 0)
define(`T_MMCTX', 1)
define(`T_STRWAIT', 2)
define(`T_STRINIT', 3)
define(`T_AUTO', 4)
define(`T_CHAN', 5)
define(`T_LOAD', 6)
define(`T_SAVE', 7)
define(`T_LCHAN', 8)
define(`T_LCTXH', 9)
define(`trace_set', `
mov $r8 0x83c
shl b32 $r8 6
clear b32 $r9
bset $r9 $1
iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
')
define(`trace_clr', `
mov $r8 0x85c
shl b32 $r8 6
clear b32 $r9
bset $r9 $1
iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
')
// queue_put - add request to queue
//
// In : $r13 queue pointer
// $r14 command
// $r15 data
//
queue_put:
// make sure we have space..
ld b32 $r8 D[$r13 + 0x0] // GET
ld b32 $r9 D[$r13 + 0x4] // PUT
xor $r8 8
cmpu b32 $r8 $r9
bra ne queue_put_next
mov $r15 E_CMD_OVERFLOW
call error
ret
// store cmd/data on queue
queue_put_next:
and $r8 $r9 7
shl b32 $r8 3
add b32 $r8 $r13
add b32 $r8 8
st b32 D[$r8 + 0x0] $r14
st b32 D[$r8 + 0x4] $r15
// update PUT
add b32 $r9 1
and $r9 0xf
st b32 D[$r13 + 0x4] $r9
ret
// queue_get - fetch request from queue
//
// In : $r13 queue pointer
//
// Out: $p1 clear on success (data available)
// $r14 command
// $r15 data
//
queue_get:
bset $flags $p1
ld b32 $r8 D[$r13 + 0x0] // GET
ld b32 $r9 D[$r13 + 0x4] // PUT
cmpu b32 $r8 $r9
bra e queue_get_done
// fetch first cmd/data pair
and $r9 $r8 7
shl b32 $r9 3
add b32 $r9 $r13
add b32 $r9 8
ld b32 $r14 D[$r9 + 0x0]
ld b32 $r15 D[$r9 + 0x4]
// update GET
add b32 $r8 1
and $r8 0xf
st b32 D[$r13 + 0x0] $r8
bclr $flags $p1
queue_get_done:
ret
// nv_rd32 - read 32-bit value from nv register
//
// In : $r14 register
// Out: $r15 value
//
nv_rd32:
mov $r11 0x728
shl b32 $r11 6
mov b32 $r12 $r14
bset $r12 31 // MMIO_CTRL_PENDING
iowr I[$r11 + 0x000] $r12 // MMIO_CTRL
nv_rd32_wait:
iord $r12 I[$r11 + 0x000]
xbit $r12 $r12 31
bra ne nv_rd32_wait
mov $r10 6 // DONE_MMIO_RD
call wait_doneo
iord $r15 I[$r11 + 0x100] // MMIO_RDVAL
ret
// nv_wr32 - write 32-bit value to nv register
//
// In : $r14 register
// $r15 value
//
nv_wr32:
mov $r11 0x728
shl b32 $r11 6
iowr I[$r11 + 0x200] $r15 // MMIO_WRVAL
mov b32 $r12 $r14
bset $r12 31 // MMIO_CTRL_PENDING
bset $r12 30 // MMIO_CTRL_WRITE
iowr I[$r11 + 0x000] $r12 // MMIO_CTRL
nv_wr32_wait:
iord $r12 I[$r11 + 0x000]
xbit $r12 $r12 31
bra ne nv_wr32_wait
ret
// (re)set watchdog timer
//
// In : $r15 timeout
//
watchdog_reset:
mov $r8 0x430
shl b32 $r8 6
bset $r15 31
iowr I[$r8 + 0x000] $r15
ret
// clear watchdog timer
watchdog_clear:
mov $r8 0x430
shl b32 $r8 6
iowr I[$r8 + 0x000] $r0
ret
// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
//
// In : $r10 bit to wait on
//
define(`wait_done', `
$1:
trace_set(T_WAIT);
mov $r8 0x818
shl b32 $r8 6
iowr I[$r8 + 0x000] $r10 // CC_SCRATCH[6] = wait bit
wait_done_$1:
mov $r8 0x400
shl b32 $r8 6
iord $r8 I[$r8 + 0x000] // DONE
xbit $r8 $r8 $r10
bra $2 wait_done_$1
trace_clr(T_WAIT)
ret
')
wait_done(wait_donez, ne)
wait_done(wait_doneo, e)
// mmctx_size - determine size of a mmio list transfer
//
// In : $r14 mmio list head
// $r15 mmio list tail
// Out: $r15 transfer size (in bytes)
//
mmctx_size:
clear b32 $r9
nv_mmctx_size_loop:
ld b32 $r8 D[$r14]
shr b32 $r8 26
add b32 $r8 1
shl b32 $r8 2
add b32 $r9 $r8
add b32 $r14 4
cmpu b32 $r14 $r15
bra ne nv_mmctx_size_loop
mov b32 $r15 $r9
ret
// mmctx_xfer - execute a list of mmio transfers
//
// In : $r10 flags
// bit 0: direction (0 = save, 1 = load)
// bit 1: set if first transfer
// bit 2: set if last transfer
// $r11 base
// $r12 mmio list head
// $r13 mmio list tail
// $r14 multi_stride
// $r15 multi_mask
//
mmctx_xfer:
trace_set(T_MMCTX)
mov $r8 0x710
shl b32 $r8 6
clear b32 $r9
or $r11 $r11
bra e mmctx_base_disabled
iowr I[$r8 + 0x000] $r11 // MMCTX_BASE
bset $r9 0 // BASE_EN
mmctx_base_disabled:
or $r14 $r14
bra e mmctx_multi_disabled
iowr I[$r8 + 0x200] $r14 // MMCTX_MULTI_STRIDE
iowr I[$r8 + 0x300] $r15 // MMCTX_MULTI_MASK
bset $r9 1 // MULTI_EN
mmctx_multi_disabled:
add b32 $r8 0x100
xbit $r11 $r10 0
shl b32 $r11 16 // DIR
bset $r11 12 // QLIMIT = 0x10
xbit $r14 $r10 1
shl b32 $r14 17
or $r11 $r14 // START_TRIGGER
iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL
// loop over the mmio list, and send requests to the hw
mmctx_exec_loop:
// wait for space in mmctx queue
mmctx_wait_free:
iord $r14 I[$r8 + 0x000] // MMCTX_CTRL
and $r14 0x1f
bra e mmctx_wait_free
// queue up an entry
ld b32 $r14 D[$r12]
or $r14 $r9
iowr I[$r8 + 0x300] $r14
add b32 $r12 4
cmpu b32 $r12 $r13
bra ne mmctx_exec_loop
xbit $r11 $r10 2
bra ne mmctx_stop
// wait for queue to empty
mmctx_fini_wait:
iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
and $r11 0x1f
cmpu b32 $r11 0x10
bra ne mmctx_fini_wait
mov $r10 2 // DONE_MMCTX
call wait_donez
bra mmctx_done
mmctx_stop:
xbit $r11 $r10 0
shl b32 $r11 16 // DIR
bset $r11 12 // QLIMIT = 0x10
bset $r11 18 // STOP_TRIGGER
iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL
mmctx_stop_wait:
// wait for STOP_TRIGGER to clear
iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
xbit $r11 $r11 18
bra ne mmctx_stop_wait
mmctx_done:
trace_clr(T_MMCTX)
ret
// Wait for DONE_STRAND
//
strand_wait:
push $r10
mov $r10 2
call wait_donez
pop $r10
ret
// unknown - call before issuing strand commands
//
strand_pre:
mov $r8 0x4afc
sethi $r8 0x20000
mov $r9 0xc
iowr I[$r8] $r9
call strand_wait
ret
// unknown - call after issuing strand commands
//
strand_post:
mov $r8 0x4afc
sethi $r8 0x20000
mov $r9 0xd
iowr I[$r8] $r9
call strand_wait
ret
// Selects strand set?!
//
// In: $r14 id
//
strand_set:
mov $r10 0x4ffc
sethi $r10 0x20000
sub b32 $r11 $r10 0x500
mov $r12 0xf
iowr I[$r10 + 0x000] $r12 // 0x93c = 0xf
mov $r12 0xb
iowr I[$r11 + 0x000] $r12 // 0x928 = 0xb
call strand_wait
iowr I[$r10 + 0x000] $r14 // 0x93c = <id>
mov $r12 0xa
iowr I[$r11 + 0x000] $r12 // 0x928 = 0xa
call strand_wait
ret
// Initialise strand context data
//
// In : $r15 context base
// Out: $r15 context size (in bytes)
//
// Strandset(?) 3 hardcoded currently
//
strand_ctx_init:
trace_set(T_STRINIT)
call strand_pre
mov $r14 3
call strand_set
mov $r10 0x46fc
sethi $r10 0x20000
add b32 $r11 $r10 0x400
iowr I[$r10 + 0x100] $r0 // STRAND_FIRST_GENE = 0
mov $r12 1
iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_FIRST_GENE
call strand_wait
sub b32 $r12 $r0 1
iowr I[$r10 + 0x000] $r12 // STRAND_GENE_CNT = 0xffffffff
mov $r12 2
iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_GENE_CNT
call strand_wait
call strand_post
// read the size of each strand, poke the context offset of
// each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
// about it later then.
mov $r8 0x880
shl b32 $r8 6
iord $r9 I[$r8 + 0x000] // STRANDS
add b32 $r8 0x2200
shr b32 $r14 $r15 8
ctx_init_strand_loop:
iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE
iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE
iord $r10 I[$r8 + 0x200] // STRAND_SIZE
shr b32 $r10 6
add b32 $r10 1
add b32 $r14 $r10
add b32 $r8 4
sub b32 $r9 1
bra ne ctx_init_strand_loop
shl b32 $r14 8
sub b32 $r15 $r14 $r15
trace_clr(T_STRINIT)
ret
')
/* fuc microcode for nvc0 PGRAPH/GPC
*
* Copyright 2011 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
*/
/* To build:
* m4 nvc0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grgpc.fuc.h
*/
/* TODO
* - bracket certain functions with scratch writes, useful for debugging
* - watchdog timer around ctx operations
*/
.section nvc0_grgpc_data
include(`nvc0_graph.fuc')
gpc_id: .b32 0
gpc_mmio_list_head: .b32 0
gpc_mmio_list_tail: .b32 0
tpc_count: .b32 0
tpc_mask: .b32 0
tpc_mmio_list_head: .b32 0
tpc_mmio_list_tail: .b32 0
cmd_queue: queue_init
// chipset descriptions
chipsets:
.b8 0xc0 0 0 0
.b16 nvc0_gpc_mmio_head
.b16 nvc0_gpc_mmio_tail
.b16 nvc0_tpc_mmio_head
.b16 nvc0_tpc_mmio_tail
.b8 0xc1 0 0 0
.b16 nvc0_gpc_mmio_head
.b16 nvc1_gpc_mmio_tail
.b16 nvc0_tpc_mmio_head
.b16 nvc1_tpc_mmio_tail
.b8 0xc3 0 0 0
.b16 nvc0_gpc_mmio_head
.b16 nvc0_gpc_mmio_tail
.b16 nvc0_tpc_mmio_head
.b16 nvc3_tpc_mmio_tail
.b8 0xc4 0 0 0
.b16 nvc0_gpc_mmio_head
.b16 nvc0_gpc_mmio_tail
.b16 nvc0_tpc_mmio_head
.b16 nvc3_tpc_mmio_tail
.b8 0xc8 0 0 0
.b16 nvc0_gpc_mmio_head
.b16 nvc0_gpc_mmio_tail
.b16 nvc0_tpc_mmio_head
.b16 nvc0_tpc_mmio_tail
.b8 0xce 0 0 0
.b16 nvc0_gpc_mmio_head
.b16 nvc0_gpc_mmio_tail
.b16 nvc0_tpc_mmio_head
.b16 nvc3_tpc_mmio_tail
.b8 0 0 0 0
// GPC mmio lists
nvc0_gpc_mmio_head:
mmctx_data(0x000380, 1)
mmctx_data(0x000400, 6)
mmctx_data(0x000450, 9)
mmctx_data(0x000600, 1)
mmctx_data(0x000684, 1)
mmctx_data(0x000700, 5)
mmctx_data(0x000800, 1)
mmctx_data(0x000808, 3)
mmctx_data(0x000828, 1)
mmctx_data(0x000830, 1)
mmctx_data(0x0008d8, 1)
mmctx_data(0x0008e0, 1)
mmctx_data(0x0008e8, 6)
mmctx_data(0x00091c, 1)
mmctx_data(0x000924, 3)
mmctx_data(0x000b00, 1)
mmctx_data(0x000b08, 6)
mmctx_data(0x000bb8, 1)
mmctx_data(0x000c08, 1)
mmctx_data(0x000c10, 8)
mmctx_data(0x000c80, 1)
mmctx_data(0x000c8c, 1)
mmctx_data(0x001000, 3)
mmctx_data(0x001014, 1)
nvc0_gpc_mmio_tail:
mmctx_data(0x000c6c, 1);
nvc1_gpc_mmio_tail:
// TPC mmio lists
nvc0_tpc_mmio_head:
mmctx_data(0x000018, 1)
mmctx_data(0x00003c, 1)
mmctx_data(0x000048, 1)
mmctx_data(0x000064, 1)
mmctx_data(0x000088, 1)
mmctx_data(0x000200, 6)
mmctx_data(0x00021c, 2)
mmctx_data(0x000300, 6)
mmctx_data(0x0003d0, 1)
mmctx_data(0x0003e0, 2)
mmctx_data(0x000400, 3)
mmctx_data(0x000420, 1)
mmctx_data(0x0004b0, 1)
mmctx_data(0x0004e8, 1)
mmctx_data(0x0004f4, 1)
mmctx_data(0x000520, 2)
mmctx_data(0x000604, 4)
mmctx_data(0x000644, 20)
mmctx_data(0x000698, 1)
mmctx_data(0x000750, 2)
nvc0_tpc_mmio_tail:
mmctx_data(0x000758, 1)
mmctx_data(0x0002c4, 1)
mmctx_data(0x0004bc, 1)
mmctx_data(0x0006e0, 1)
nvc3_tpc_mmio_tail:
mmctx_data(0x000544, 1)
nvc1_tpc_mmio_tail:
.section nvc0_grgpc_code
bra init
define(`include_code')
include(`nvc0_graph.fuc')
// reports an exception to the host
//
// In: $r15 error code (see nvc0_graph.fuc)
//
error:
push $r14
mov $r14 -0x67ec // 0x9814
sethi $r14 0x400000
call nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code
add b32 $r14 0x41c
mov $r15 1
call nv_wr32 // HUB_CTXCTL_INTR_UP_SET
pop $r14
ret
// GPC fuc initialisation, executed by triggering ucode start, will
// fall through to main loop after completion.
//
// Input:
// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
// CC_SCRATCH[1]: context base
//
// Output:
// CC_SCRATCH[0]:
// 31:31: set to signal completion
// CC_SCRATCH[1]:
// 31:0: GPC context size
//
init:
clear b32 $r0
mov $sp $r0
// enable fifo access
mov $r1 0x1200
mov $r2 2
iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
// setup i0 handler, and route all interrupts to it
mov $r1 ih
mov $iv0 $r1
mov $r1 0x400
iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
// enable fifo interrupt
mov $r2 4
iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
// enable interrupts
bset $flags ie0
// figure out which GPC we are, and how many TPCs we have
mov $r1 0x608
shl b32 $r1 6
iord $r2 I[$r1 + 0x000] // UNITS
mov $r3 1
and $r2 0x1f
shl b32 $r3 $r2
sub b32 $r3 1
st b32 D[$r0 + tpc_count] $r2
st b32 D[$r0 + tpc_mask] $r3
add b32 $r1 0x400
iord $r2 I[$r1 + 0x000] // MYINDEX
st b32 D[$r0 + gpc_id] $r2
// find context data for this chipset
mov $r2 0x800
shl b32 $r2 6
iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
mov $r1 chipsets - 12
init_find_chipset:
add b32 $r1 12
ld b32 $r3 D[$r1 + 0x00]
cmpu b32 $r3 $r2
bra e init_context
cmpu b32 $r3 0
bra ne init_find_chipset
// unknown chipset
ret
// initialise context base, and size tracking
init_context:
mov $r2 0x800
shl b32 $r2 6
iord $r2 I[$r2 + 0x100] // CC_SCRATCH[1], initial base
clear b32 $r3 // track GPC context size here
// set mmctx base addresses now so we don't have to do it later,
// they don't currently ever change
mov $r4 0x700
shl b32 $r4 6
shr b32 $r5 $r2 8
iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE
iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE
// calculate GPC mmio context size, store the chipset-specific
// mmio list pointers somewhere we can get at them later without
// re-parsing the chipset list
clear b32 $r14
clear b32 $r15
ld b16 $r14 D[$r1 + 4]
ld b16 $r15 D[$r1 + 6]
st b16 D[$r0 + gpc_mmio_list_head] $r14
st b16 D[$r0 + gpc_mmio_list_tail] $r15
call mmctx_size
add b32 $r2 $r15
add b32 $r3 $r15
// calculate per-TPC mmio context size, store the list pointers
ld b16 $r14 D[$r1 + 8]
ld b16 $r15 D[$r1 + 10]
st b16 D[$r0 + tpc_mmio_list_head] $r14
st b16 D[$r0 + tpc_mmio_list_tail] $r15
call mmctx_size
ld b32 $r14 D[$r0 + tpc_count]
mulu $r14 $r15
add b32 $r2 $r14
add b32 $r3 $r14
// round up base/size to 256 byte boundary (for strand SWBASE)
add b32 $r4 0x1300
shr b32 $r3 2
iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!?
shr b32 $r2 8
shr b32 $r3 6
add b32 $r2 1
add b32 $r3 1
shl b32 $r2 8
shl b32 $r3 8
// calculate size of strand context data
mov b32 $r15 $r2
call strand_ctx_init
add b32 $r3 $r15
// save context size, and tell HUB we're done
mov $r1 0x800
shl b32 $r1 6
iowr I[$r1 + 0x100] $r3 // CC_SCRATCH[1] = context size
add b32 $r1 0x800
clear b32 $r2
bset $r2 31
iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
// Main program loop, very simple, sleeps until woken up by the interrupt
// handler, pulls a command from the queue and executes its handler
//
main:
bset $flags $p0
sleep $p0
mov $r13 cmd_queue
call queue_get
bra $p1 main
// 0x0000-0x0003 are all context transfers
cmpu b32 $r14 0x04
bra nc main_not_ctx_xfer
// fetch $flags and mask off $p1/$p2
mov $r1 $flags
mov $r2 0x0006
not b32 $r2
and $r1 $r2
// set $p1/$p2 according to transfer type
shl b32 $r14 1
or $r1 $r14
mov $flags $r1
// transfer context data
call ctx_xfer
bra main
main_not_ctx_xfer:
shl b32 $r15 $r14 16
or $r15 E_BAD_COMMAND
call error
bra main
// interrupt handler
ih:
push $r8
mov $r8 $flags
push $r8
push $r9
push $r10
push $r11
push $r13
push $r14
push $r15
// incoming fifo command?
iord $r10 I[$r0 + 0x200] // INTR
and $r11 $r10 0x00000004
bra e ih_no_fifo
// queue incoming fifo command for later processing
mov $r11 0x1900
mov $r13 cmd_queue
iord $r14 I[$r11 + 0x100] // FIFO_CMD
iord $r15 I[$r11 + 0x000] // FIFO_DATA
call queue_put
add b32 $r11 0x400
mov $r14 1
iowr I[$r11 + 0x000] $r14 // FIFO_ACK
// ack, and wake up main()
ih_no_fifo:
iowr I[$r0 + 0x100] $r10 // INTR_ACK
pop $r15
pop $r14
pop $r13
pop $r11
pop $r10
pop $r9
pop $r8
mov $flags $r8
pop $r8
bclr $flags $p0
iret
// Set this GPC's bit in HUB_BAR, used to signal completion of various
// activities to the HUB fuc
//
hub_barrier_done:
mov $r15 1
ld b32 $r14 D[$r0 + gpc_id]
shl b32 $r15 $r14
mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET
sethi $r14 0x400000
call nv_wr32
ret
// Disables various things, waits a bit, and re-enables them..
//
// Not sure how exactly this helps, perhaps "ENABLE" is not such a
// good description for the bits we turn off? Anyways, without this,
// funny things happen.
//
ctx_redswitch:
mov $r14 0x614
shl b32 $r14 6
mov $r15 0x020
iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER
mov $r15 8
ctx_redswitch_delay:
sub b32 $r15 1
bra ne ctx_redswitch_delay
mov $r15 0xa20
iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER
ret
// Transfer GPC context data between GPU and storage area
//
// In: $r15 context base address
// $p1 clear on save, set on load
// $p2 set if opposite direction done/will be done, so:
// on save it means: "a load will follow this save"
// on load it means: "a save preceeded this load"
//
ctx_xfer:
// set context base address
mov $r1 0xa04
shl b32 $r1 6
iowr I[$r1 + 0x000] $r15// MEM_BASE
bra not $p1 ctx_xfer_not_load
call ctx_redswitch
ctx_xfer_not_load:
// strands
mov $r1 0x4afc
sethi $r1 0x20000
mov $r2 0xc
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
call strand_wait
mov $r2 0x47fc
sethi $r2 0x20000
iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
xbit $r2 $flags $p1
add b32 $r2 3
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
// mmio context
xbit $r10 $flags $p1 // direction
or $r10 2 // first
mov $r11 0x0000
sethi $r11 0x500000
ld b32 $r12 D[$r0 + gpc_id]
shl b32 $r12 15
add b32 $r11 $r12 // base = NV_PGRAPH_GPCn
ld b32 $r12 D[$r0 + gpc_mmio_list_head]
ld b32 $r13 D[$r0 + gpc_mmio_list_tail]
mov $r14 0 // not multi
call mmctx_xfer
// per-TPC mmio context
xbit $r10 $flags $p1 // direction
or $r10 4 // last
mov $r11 0x4000
sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0
ld b32 $r12 D[$r0 + gpc_id]
shl b32 $r12 15
add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0
ld b32 $r12 D[$r0 + tpc_mmio_list_head]
ld b32 $r13 D[$r0 + tpc_mmio_list_tail]
ld b32 $r15 D[$r0 + tpc_mask]
mov $r14 0x800 // stride = 0x800
call mmctx_xfer
// wait for strands to finish
call strand_wait
// if load, or a save without a load following, do some
// unknown stuff that's done after finishing a block of
// strand commands
bra $p1 ctx_xfer_post
bra not $p2 ctx_xfer_done
ctx_xfer_post:
mov $r1 0x4afc
sethi $r1 0x20000
mov $r2 0xd
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d
call strand_wait
// mark completion in HUB's barrier
ctx_xfer_done:
call hub_barrier_done
ret
.align 256
uint32_t nvc0_grgpc_data[] = {
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x000000c0,
0x011000b0,
0x01640114,
0x000000c1,
0x011400b0,
0x01780114,
0x000000c3,
0x011000b0,
0x01740114,
0x000000c4,
0x011000b0,
0x01740114,
0x000000c8,
0x011000b0,
0x01640114,
0x000000ce,
0x011000b0,
0x01740114,
0x00000000,
0x00000380,
0x14000400,
0x20000450,
0x00000600,
0x00000684,
0x10000700,
0x00000800,
0x08000808,
0x00000828,
0x00000830,
0x000008d8,
0x000008e0,
0x140008e8,
0x0000091c,
0x08000924,
0x00000b00,
0x14000b08,
0x00000bb8,
0x00000c08,
0x1c000c10,
0x00000c80,
0x00000c8c,
0x08001000,
0x00001014,
0x00000c6c,
0x00000018,
0x0000003c,
0x00000048,
0x00000064,
0x00000088,
0x14000200,
0x0400021c,
0x14000300,
0x000003d0,
0x040003e0,
0x08000400,
0x00000420,
0x000004b0,
0x000004e8,
0x000004f4,
0x04000520,
0x0c000604,
0x4c000644,
0x00000698,
0x04000750,
0x00000758,
0x000002c4,
0x000004bc,
0x000006e0,
0x00000544,
};
uint32_t nvc0_grgpc_code[] = {
0x03060ef5,
0x9800d898,
0x86f001d9,
0x0489b808,
0xf00c1bf4,
0x21f502f7,
0x00f802ec,
0xb60798c4,
0x8dbb0384,
0x0880b600,
0x80008e80,
0x90b6018f,
0x0f94f001,
0xf801d980,
0x0131f400,
0x9800d898,
0x89b801d9,
0x210bf404,
0xb60789c4,
0x9dbb0394,
0x0890b600,
0x98009e98,
0x80b6019f,
0x0f84f001,
0xf400d880,
0x00f80132,
0x0728b7f1,
0xb906b4b6,
0xc9f002ec,
0x00bcd01f,
0xc800bccf,
0x1bf41fcc,
0x06a7f0fa,
0x010321f5,
0xf840bfcf,
0x28b7f100,
0x06b4b607,
0xb980bfd0,
0xc9f002ec,
0x1ec9f01f,
0xcf00bcd0,
0xccc800bc,
0xfa1bf41f,
0x87f100f8,
0x84b60430,
0x1ff9f006,
0xf8008fd0,
0x3087f100,
0x0684b604,
0xf80080d0,
0x3c87f100,
0x0684b608,
0x99f094bd,
0x0089d000,
0x081887f1,
0xd00684b6,
0x87f1008a,
0x84b60400,
0x0088cf06,
0xf4888aff,
0x87f1f31b,
0x84b6085c,
0xf094bd06,
0x89d00099,
0xf100f800,
0xb6083c87,
0x94bd0684,
0xd00099f0,
0x87f10089,
0x84b60818,
0x008ad006,
0x040087f1,
0xcf0684b6,
0x8aff0088,
0xf30bf488,
0x085c87f1,
0xbd0684b6,
0x0099f094,
0xf80089d0,
0x9894bd00,
0x85b600e8,
0x0180b61a,
0xbb0284b6,
0xe0b60098,
0x04efb804,
0xb9eb1bf4,
0x00f8029f,
0x083c87f1,
0xbd0684b6,
0x0199f094,
0xf10089d0,
0xb6071087,
0x94bd0684,
0xf405bbfd,
0x8bd0090b,
0x0099f000,
0xf405eefd,
0x8ed00c0b,
0xc08fd080,
0xb70199f0,
0xc8010080,
0xb4b600ab,
0x0cb9f010,
0xb601aec8,
0xbefd11e4,
0x008bd005,
0xf0008ecf,
0x0bf41fe4,
0x00ce98fa,
0xd005e9fd,
0xc0b6c08e,
0x04cdb804,
0xc8e81bf4,
0x1bf402ab,
0x008bcf18,
0xb01fb4f0,
0x1bf410b4,
0x02a7f0f7,
0xf4c921f4,
0xabc81b0e,
0x10b4b600,
0xf00cb9f0,
0x8bd012b9,
0x008bcf00,
0xf412bbc8,
0x87f1fa1b,
0x84b6085c,
0xf094bd06,
0x89d00199,
0xf900f800,
0x02a7f0a0,
0xfcc921f4,
0xf100f8a0,
0xf04afc87,
0x97f00283,
0x0089d00c,
0x020721f5,
0x87f100f8,
0x83f04afc,
0x0d97f002,
0xf50089d0,
0xf8020721,
0xfca7f100,
0x02a3f04f,
0x0500aba2,
0xd00fc7f0,
0xc7f000ac,
0x00bcd00b,
0x020721f5,
0xf000aed0,
0xbcd00ac7,
0x0721f500,
0xf100f802,
0xb6083c87,
0x94bd0684,
0xd00399f0,
0x21f50089,
0xe7f00213,
0x3921f503,
0xfca7f102,
0x02a3f046,
0x0400aba0,
0xf040a0d0,
0xbcd001c7,
0x0721f500,
0x010c9202,
0xf000acd0,
0xbcd002c7,
0x0721f500,
0x2621f502,
0x8087f102,
0x0684b608,
0xb70089cf,
0x95220080,
0x8ed008fe,
0x408ed000,
0xb6808acf,
0xa0b606a5,
0x00eabb01,
0xb60480b6,
0x1bf40192,
0x08e4b6e8,
0xf1f2efbc,
0xb6085c87,
0x94bd0684,
0xd00399f0,
0x00f80089,
0xe7f1e0f9,
0xe3f09814,
0x8d21f440,
0x041ce0b7,
0xf401f7f0,
0xe0fc8d21,
0x04bd00f8,
0xf10004fe,
0xf0120017,
0x12d00227,
0x3e17f100,
0x0010fe04,
0x040017f1,
0xf0c010d0,
0x12d00427,
0x1031f400,
0x060817f1,
0xcf0614b6,
0x37f00012,
0x1f24f001,
0xb60432bb,
0x02800132,
0x04038003,
0x040010b7,
0x800012cf,
0x27f10002,
0x24b60800,
0x0022cf06,
0xb65817f0,
0x13980c10,
0x0432b800,
0xb00b0bf4,
0x1bf40034,
0xf100f8f1,
0xb6080027,
0x22cf0624,
0xf134bd40,
0xb6070047,
0x25950644,
0x0045d008,
0xbd4045d0,
0x58f4bde4,
0x1f58021e,
0x020e4003,
0xf5040f40,
0xbb013d21,
0x3fbb002f,
0x041e5800,
0x40051f58,
0x0f400a0e,
0x3d21f50c,
0x030e9801,
0xbb00effd,
0x3ebb002e,
0x0040b700,
0x0235b613,
0xb60043d0,
0x35b60825,
0x0120b606,
0xb60130b6,
0x34b60824,
0x022fb908,
0x026321f5,
0xf1003fbb,
0xb6080017,
0x13d00614,
0x0010b740,
0xf024bd08,
0x12d01f29,
0x0031f400,
0xf00028f4,
0x21f41cd7,
0xf401f439,
0xf404e4b0,
0x81fe1e18,
0x0627f001,
0x12fd20bd,
0x01e4b604,
0xfe051efd,
0x21f50018,
0x0ef404c3,
0x10ef94d3,
0xf501f5f0,
0xf402ec21,
0x80f9c60e,
0xf90188fe,
0xf990f980,
0xf9b0f9a0,
0xf9e0f9d0,
0x800acff0,
0xf404abc4,
0xb7f11d0b,
0xd7f01900,
0x40becf1c,
0xf400bfcf,
0xb0b70421,
0xe7f00400,
0x00bed001,
0xfc400ad0,
0xfce0fcf0,
0xfcb0fcd0,
0xfc90fca0,
0x0088fe80,
0x32f480fc,
0xf001f800,
0x0e9801f7,
0x04febb00,
0x9418e7f1,
0xf440e3f0,
0x00f88d21,
0x0614e7f1,
0xf006e4b6,
0xefd020f7,
0x08f7f000,
0xf401f2b6,
0xf7f1fd1b,
0xefd00a20,
0xf100f800,
0xb60a0417,
0x1fd00614,
0x0711f400,
0x04a421f5,
0x4afc17f1,
0xf00213f0,
0x12d00c27,
0x0721f500,
0xfc27f102,
0x0223f047,
0xf00020d0,
0x20b6012c,
0x0012d003,
0xf001acf0,
0xb7f002a5,
0x50b3f000,
0xb6000c98,
0xbcbb0fc4,
0x010c9800,
0xf0020d98,
0x21f500e7,
0xacf0015c,
0x04a5f001,
0x4000b7f1,
0x9850b3f0,
0xc4b6000c,
0x00bcbb0f,
0x98050c98,
0x0f98060d,
0x00e7f104,
0x5c21f508,
0x0721f501,
0x0601f402,
0xf11412f4,
0xf04afc17,
0x27f00213,
0x0012d00d,
0x020721f5,
0x048f21f5,
0x000000f8,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
/* fuc microcode for nvc0 PGRAPH/HUB
*
* Copyright 2011 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
*/
/* To build:
* m4 nvc0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grhub.fuc.h
*/
.section nvc0_grhub_data
include(`nvc0_graph.fuc')
gpc_count: .b32 0
rop_count: .b32 0
cmd_queue: queue_init
hub_mmio_list_head: .b32 0
hub_mmio_list_tail: .b32 0
ctx_current: .b32 0
chipsets:
.b8 0xc0 0 0 0
.b16 nvc0_hub_mmio_head
.b16 nvc0_hub_mmio_tail
.b8 0xc1 0 0 0
.b16 nvc0_hub_mmio_head
.b16 nvc1_hub_mmio_tail
.b8 0xc3 0 0 0
.b16 nvc0_hub_mmio_head
.b16 nvc0_hub_mmio_tail
.b8 0xc4 0 0 0
.b16 nvc0_hub_mmio_head
.b16 nvc0_hub_mmio_tail
.b8 0xc8 0 0 0
.b16 nvc0_hub_mmio_head
.b16 nvc0_hub_mmio_tail
.b8 0xce 0 0 0
.b16 nvc0_hub_mmio_head
.b16 nvc0_hub_mmio_tail
.b8 0 0 0 0
nvc0_hub_mmio_head:
mmctx_data(0x17e91c, 2)
mmctx_data(0x400204, 2)
mmctx_data(0x404004, 11)
mmctx_data(0x404044, 1)
mmctx_data(0x404094, 14)
mmctx_data(0x4040d0, 7)
mmctx_data(0x4040f8, 1)
mmctx_data(0x404130, 3)
mmctx_data(0x404150, 3)
mmctx_data(0x404164, 2)
mmctx_data(0x404174, 3)
mmctx_data(0x404200, 8)
mmctx_data(0x404404, 14)
mmctx_data(0x404460, 4)
mmctx_data(0x404480, 1)
mmctx_data(0x404498, 1)
mmctx_data(0x404604, 4)
mmctx_data(0x404618, 32)
mmctx_data(0x404698, 21)
mmctx_data(0x4046f0, 2)
mmctx_data(0x404700, 22)
mmctx_data(0x405800, 1)
mmctx_data(0x405830, 3)
mmctx_data(0x405854, 1)
mmctx_data(0x405870, 4)
mmctx_data(0x405a00, 2)
mmctx_data(0x405a18, 1)
mmctx_data(0x406020, 1)
mmctx_data(0x406028, 4)
mmctx_data(0x4064a8, 2)
mmctx_data(0x4064b4, 2)
mmctx_data(0x407804, 1)
mmctx_data(0x40780c, 6)
mmctx_data(0x4078bc, 1)
mmctx_data(0x408000, 7)
mmctx_data(0x408064, 1)
mmctx_data(0x408800, 3)
mmctx_data(0x408900, 4)
mmctx_data(0x408980, 1)
nvc0_hub_mmio_tail:
mmctx_data(0x4064c0, 2)
nvc1_hub_mmio_tail:
.align 256
chan_data:
chan_mmio_count: .b32 0
chan_mmio_address: .b32 0
.align 256
xfer_data: .b32 0
.section nvc0_grhub_code
bra init
define(`include_code')
include(`nvc0_graph.fuc')
// reports an exception to the host
//
// In: $r15 error code (see nvc0_graph.fuc)
//
error:
push $r14
mov $r14 0x814
shl b32 $r14 6
iowr I[$r14 + 0x000] $r15 // CC_SCRATCH[5] = error code
mov $r14 0xc1c
shl b32 $r14 6
mov $r15 1
iowr I[$r14 + 0x000] $r15 // INTR_UP_SET
pop $r14
ret
// HUB fuc initialisation, executed by triggering ucode start, will
// fall through to main loop after completion.
//
// Input:
// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
//
// Output:
// CC_SCRATCH[0]:
// 31:31: set to signal completion
// CC_SCRATCH[1]:
// 31:0: total PGRAPH context size
//
init:
clear b32 $r0
mov $sp $r0
mov $xdbase $r0
// enable fifo access
mov $r1 0x1200
mov $r2 2
iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
// setup i0 handler, and route all interrupts to it
mov $r1 ih
mov $iv0 $r1
mov $r1 0x400
iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
// route HUB_CHANNEL_SWITCH to fuc interrupt 8
mov $r3 0x404
shl b32 $r3 6
mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
iowr I[$r3 + 0x000] $r2
// not sure what these are, route them because NVIDIA does, and
// the IRQ handler will signal the host if we ever get one.. we
// may find out if/why we need to handle these if so..
//
mov $r2 0x2004
iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
mov $r2 0x200b
iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
mov $r2 0x200c
iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
// enable all INTR_UP interrupts
mov $r2 0xc24
shl b32 $r2 6
not b32 $r3 $r0
iowr I[$r2] $r3
// enable fifo, ctxsw, 9, 10, 15 interrupts
mov $r2 -0x78fc // 0x8704
sethi $r2 0
iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
// fifo level triggered, rest edge
sub b32 $r1 0x100
mov $r2 4
iowr I[$r1] $r2
// enable interrupts
bset $flags ie0
// fetch enabled GPC/ROP counts
mov $r14 -0x69fc // 0x409604
sethi $r14 0x400000
call nv_rd32
extr $r1 $r15 16:20
st b32 D[$r0 + rop_count] $r1
and $r15 0x1f
st b32 D[$r0 + gpc_count] $r15
// set BAR_REQMASK to GPC mask
mov $r1 1
shl b32 $r1 $r15
sub b32 $r1 1
mov $r2 0x40c
shl b32 $r2 6
iowr I[$r2 + 0x000] $r1
iowr I[$r2 + 0x100] $r1
// find context data for this chipset
mov $r2 0x800
shl b32 $r2 6
iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
mov $r15 chipsets - 8
init_find_chipset:
add b32 $r15 8
ld b32 $r3 D[$r15 + 0x00]
cmpu b32 $r3 $r2
bra e init_context
cmpu b32 $r3 0
bra ne init_find_chipset
// unknown chipset
ret
// context size calculation, reserve first 256 bytes for use by fuc
init_context:
mov $r1 256
// calculate size of mmio context data
ld b16 $r14 D[$r15 + 4]
ld b16 $r15 D[$r15 + 6]
sethi $r14 0
st b32 D[$r0 + hub_mmio_list_head] $r14
st b32 D[$r0 + hub_mmio_list_tail] $r15
call mmctx_size
// set mmctx base addresses now so we don't have to do it later,
// they don't (currently) ever change
mov $r3 0x700
shl b32 $r3 6
shr b32 $r4 $r1 8
iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE
iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE
add b32 $r3 0x1300
add b32 $r1 $r15
shr b32 $r15 2
iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!?
// strands, base offset needs to be aligned to 256 bytes
shr b32 $r1 8
add b32 $r1 1
shl b32 $r1 8
mov b32 $r15 $r1
call strand_ctx_init
add b32 $r1 $r15
// initialise each GPC in sequence by passing in the offset of its
// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
// has previously been uploaded by the host) running.
//
// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
// when it has completed, and return the size of its context data
// in GPCn_CC_SCRATCH[1]
//
ld b32 $r3 D[$r0 + gpc_count]
mov $r4 0x2000
sethi $r4 0x500000
init_gpc:
// setup, and start GPC ucode running
add b32 $r14 $r4 0x804
mov b32 $r15 $r1
call nv_wr32 // CC_SCRATCH[1] = ctx offset
add b32 $r14 $r4 0x800
mov b32 $r15 $r2
call nv_wr32 // CC_SCRATCH[0] = chipset
add b32 $r14 $r4 0x10c
clear b32 $r15
call nv_wr32
add b32 $r14 $r4 0x104
call nv_wr32 // ENTRY
add b32 $r14 $r4 0x100
mov $r15 2 // CTRL_START_TRIGGER
call nv_wr32 // CTRL
// wait for it to complete, and adjust context size
add b32 $r14 $r4 0x800
init_gpc_wait:
call nv_rd32
xbit $r15 $r15 31
bra e init_gpc_wait
add b32 $r14 $r4 0x804
call nv_rd32
add b32 $r1 $r15
// next!
add b32 $r4 0x8000
sub b32 $r3 1
bra ne init_gpc
// save context size, and tell host we're ready
mov $r2 0x800
shl b32 $r2 6
iowr I[$r2 + 0x100] $r1 // CC_SCRATCH[1] = context size
add b32 $r2 0x800
clear b32 $r1
bset $r1 31
iowr I[$r2 + 0x000] $r1 // CC_SCRATCH[0] |= 0x80000000
// Main program loop, very simple, sleeps until woken up by the interrupt
// handler, pulls a command from the queue and executes its handler
//
main:
// sleep until we have something to do
bset $flags $p0
sleep $p0
mov $r13 cmd_queue
call queue_get
bra $p1 main
// context switch, requested by GPU?
cmpu b32 $r14 0x4001
bra ne main_not_ctx_switch
trace_set(T_AUTO)
mov $r1 0xb00
shl b32 $r1 6
iord $r2 I[$r1 + 0x100] // CHAN_NEXT
iord $r1 I[$r1 + 0x000] // CHAN_CUR
xbit $r3 $r1 31
bra e chsw_no_prev
xbit $r3 $r2 31
bra e chsw_prev_no_next
push $r2
mov b32 $r2 $r1
trace_set(T_SAVE)
bclr $flags $p1
bset $flags $p2
call ctx_xfer
trace_clr(T_SAVE);
pop $r2
trace_set(T_LOAD);
bset $flags $p1
call ctx_xfer
trace_clr(T_LOAD);
bra chsw_done
chsw_prev_no_next:
push $r2
mov b32 $r2 $r1
bclr $flags $p1
bclr $flags $p2
call ctx_xfer
pop $r2
mov $r1 0xb00
shl b32 $r1 6
iowr I[$r1] $r2
bra chsw_done
chsw_no_prev:
xbit $r3 $r2 31
bra e chsw_done
bset $flags $p1
bclr $flags $p2
call ctx_xfer
// ack the context switch request
chsw_done:
mov $r1 0xb0c
shl b32 $r1 6
mov $r2 1
iowr I[$r1 + 0x000] $r2 // 0x409b0c
trace_clr(T_AUTO)
bra main
// request to set current channel? (*not* a context switch)
main_not_ctx_switch:
cmpu b32 $r14 0x0001
bra ne main_not_ctx_chan
mov b32 $r2 $r15
call ctx_chan
bra main_done
// request to store current channel context?
main_not_ctx_chan:
cmpu b32 $r14 0x0002
bra ne main_not_ctx_save
trace_set(T_SAVE)
bclr $flags $p1
bclr $flags $p2
call ctx_xfer
trace_clr(T_SAVE)
bra main_done
main_not_ctx_save:
shl b32 $r15 $r14 16
or $r15 E_BAD_COMMAND
call error
bra main
main_done:
mov $r1 0x820
shl b32 $r1 6
clear b32 $r2
bset $r2 31
iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
bra main
// interrupt handler
ih:
push $r8
mov $r8 $flags
push $r8
push $r9
push $r10
push $r11
push $r13
push $r14
push $r15
// incoming fifo command?
iord $r10 I[$r0 + 0x200] // INTR
and $r11 $r10 0x00000004
bra e ih_no_fifo
// queue incoming fifo command for later processing
mov $r11 0x1900
mov $r13 cmd_queue
iord $r14 I[$r11 + 0x100] // FIFO_CMD
iord $r15 I[$r11 + 0x000] // FIFO_DATA
call queue_put
add b32 $r11 0x400
mov $r14 1
iowr I[$r11 + 0x000] $r14 // FIFO_ACK
// context switch request?
ih_no_fifo:
and $r11 $r10 0x00000100
bra e ih_no_ctxsw
// enqueue a context switch for later processing
mov $r13 cmd_queue
mov $r14 0x4001
call queue_put
// anything we didn't handle, bring it to the host's attention
ih_no_ctxsw:
mov $r11 0x104
not b32 $r11
and $r11 $r10 $r11
bra e ih_no_other
mov $r10 0xc1c
shl b32 $r10 6
iowr I[$r10] $r11 // INTR_UP_SET
// ack, and wake up main()
ih_no_other:
iowr I[$r0 + 0x100] $r10 // INTR_ACK
pop $r15
pop $r14
pop $r13
pop $r11
pop $r10
pop $r9
pop $r8
mov $flags $r8
pop $r8
bclr $flags $p0
iret
// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
ctx_4160s:
mov $r14 0x4160
sethi $r14 0x400000
mov $r15 1
call nv_wr32
ctx_4160s_wait:
call nv_rd32
xbit $r15 $r15 4
bra e ctx_4160s_wait
ret
// Without clearing again at end of xfer, some things cause PGRAPH
// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
// still function with it set however...
ctx_4160c:
mov $r14 0x4160
sethi $r14 0x400000
clear b32 $r15
call nv_wr32
ret
// Again, not real sure
//
// In: $r15 value to set 0x404170 to
//
ctx_4170s:
mov $r14 0x4170
sethi $r14 0x400000
or $r15 0x10
call nv_wr32
ret
// Waits for a ctx_4170s() call to complete
//
ctx_4170w:
mov $r14 0x4170
sethi $r14 0x400000
call nv_rd32
and $r15 0x10
bra ne ctx_4170w
ret
// Disables various things, waits a bit, and re-enables them..
//
// Not sure how exactly this helps, perhaps "ENABLE" is not such a
// good description for the bits we turn off? Anyways, without this,
// funny things happen.
//
ctx_redswitch:
mov $r14 0x614
shl b32 $r14 6
mov $r15 0x270
iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
mov $r15 8
ctx_redswitch_delay:
sub b32 $r15 1
bra ne ctx_redswitch_delay
mov $r15 0x770
iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
ret
// Not a clue what this is for, except that unless the value is 0x10, the
// strand context is saved (and presumably restored) incorrectly..
//
// In: $r15 value to set to (0x00/0x10 are used)
//
ctx_86c:
mov $r14 0x86c
shl b32 $r14 6
iowr I[$r14] $r15 // HUB(0x86c) = val
mov $r14 -0x75ec
sethi $r14 0x400000
call nv_wr32 // ROP(0xa14) = val
mov $r14 -0x5794
sethi $r14 0x410000
call nv_wr32 // GPC(0x86c) = val
ret
// ctx_load - load's a channel's ctxctl data, and selects its vm
//
// In: $r2 channel address
//
ctx_load:
trace_set(T_CHAN)
// switch to channel, somewhat magic in parts..
mov $r10 12 // DONE_UNK12
call wait_donez
mov $r1 0xa24
shl b32 $r1 6
iowr I[$r1 + 0x000] $r0 // 0x409a24
mov $r3 0xb00
shl b32 $r3 6
iowr I[$r3 + 0x100] $r2 // CHAN_NEXT
mov $r1 0xa0c
shl b32 $r1 6
mov $r4 7
iowr I[$r1 + 0x000] $r2 // MEM_CHAN
iowr I[$r1 + 0x100] $r4 // MEM_CMD
ctx_chan_wait_0:
iord $r4 I[$r1 + 0x100]
and $r4 0x1f
bra ne ctx_chan_wait_0
iowr I[$r3 + 0x000] $r2 // CHAN_CUR
// load channel header, fetch PGRAPH context pointer
mov $xtargets $r0
bclr $r2 31
shl b32 $r2 4
add b32 $r2 2
trace_set(T_LCHAN)
mov $r1 0xa04
shl b32 $r1 6
iowr I[$r1 + 0x000] $r2 // MEM_BASE
mov $r1 0xa20
shl b32 $r1 6
mov $r2 0x0002
sethi $r2 0x80000000
iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram
mov $r1 0x10 // chan + 0x0210
mov $r2 xfer_data
sethi $r2 0x00020000 // 16 bytes
xdld $r1 $r2
xdwait
trace_clr(T_LCHAN)
// update current context
ld b32 $r1 D[$r0 + xfer_data + 4]
shl b32 $r1 24
ld b32 $r2 D[$r0 + xfer_data + 0]
shr b32 $r2 8
or $r1 $r2
st b32 D[$r0 + ctx_current] $r1
// set transfer base to start of context, and fetch context header
trace_set(T_LCTXH)
mov $r2 0xa04
shl b32 $r2 6
iowr I[$r2 + 0x000] $r1 // MEM_BASE
mov $r2 1
mov $r1 0xa20
shl b32 $r1 6
iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm
mov $r1 chan_data
sethi $r1 0x00060000 // 256 bytes
xdld $r0 $r1
xdwait
trace_clr(T_LCTXH)
trace_clr(T_CHAN)
ret
// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
// the active channel for ctxctl, but not actually transfer
// any context data. intended for use only during initial
// context construction.
//
// In: $r2 channel address
//
ctx_chan:
call ctx_4160s
call ctx_load
mov $r10 12 // DONE_UNK12
call wait_donez
mov $r1 0xa10
shl b32 $r1 6
mov $r2 5
iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???)
ctx_chan_wait:
iord $r2 I[$r1 + 0x000]
or $r2 $r2
bra ne ctx_chan_wait
call ctx_4160c
ret
// Execute per-context state overrides list
//
// Only executed on the first load of a channel. Might want to look into
// removing this and having the host directly modify the channel's context
// to change this state... The nouveau DRM already builds this list as
// it's definitely needed for NVIDIA's, so we may as well use it for now
//
// Input: $r1 mmio list length
//
ctx_mmio_exec:
// set transfer base to be the mmio list
ld b32 $r3 D[$r0 + chan_mmio_address]
mov $r2 0xa04
shl b32 $r2 6
iowr I[$r2 + 0x000] $r3 // MEM_BASE
clear b32 $r3
ctx_mmio_loop:
// fetch next 256 bytes of mmio list if necessary
and $r4 $r3 0xff
bra ne ctx_mmio_pull
mov $r5 xfer_data
sethi $r5 0x00060000 // 256 bytes
xdld $r3 $r5
xdwait
// execute a single list entry
ctx_mmio_pull:
ld b32 $r14 D[$r4 + xfer_data + 0x00]
ld b32 $r15 D[$r4 + xfer_data + 0x04]
call nv_wr32
// next!
add b32 $r3 8
sub b32 $r1 1
bra ne ctx_mmio_loop
// set transfer base back to the current context
ctx_mmio_done:
ld b32 $r3 D[$r0 + ctx_current]
iowr I[$r2 + 0x000] $r3 // MEM_BASE
// disable the mmio list now, we don't need/want to execute it again
st b32 D[$r0 + chan_mmio_count] $r0
mov $r1 chan_data
sethi $r1 0x00060000 // 256 bytes
xdst $r0 $r1
xdwait
ret
// Transfer HUB context data between GPU and storage area
//
// In: $r2 channel address
// $p1 clear on save, set on load
// $p2 set if opposite direction done/will be done, so:
// on save it means: "a load will follow this save"
// on load it means: "a save preceeded this load"
//
ctx_xfer:
bra not $p1 ctx_xfer_pre
bra $p2 ctx_xfer_pre_load
ctx_xfer_pre:
mov $r15 0x10
call ctx_86c
call ctx_4160s
bra not $p1 ctx_xfer_exec
ctx_xfer_pre_load:
mov $r15 2
call ctx_4170s
call ctx_4170w
call ctx_redswitch
clear b32 $r15
call ctx_4170s
call ctx_load
// fetch context pointer, and initiate xfer on all GPCs
ctx_xfer_exec:
ld b32 $r1 D[$r0 + ctx_current]
mov $r2 0x414
shl b32 $r2 6
iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset
mov $r14 -0x5b00
sethi $r14 0x410000
mov b32 $r15 $r1
call nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer
add b32 $r14 4
xbit $r15 $flags $p1
xbit $r2 $flags $p2
shl b32 $r2 1
or $r15 $r2
call nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
// strands
mov $r1 0x4afc
sethi $r1 0x20000
mov $r2 0xc
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
call strand_wait
mov $r2 0x47fc
sethi $r2 0x20000
iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
xbit $r2 $flags $p1
add b32 $r2 3
iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
// mmio context
xbit $r10 $flags $p1 // direction
or $r10 6 // first, last
mov $r11 0 // base = 0
ld b32 $r12 D[$r0 + hub_mmio_list_head]
ld b32 $r13 D[$r0 + hub_mmio_list_tail]
mov $r14 0 // not multi
call mmctx_xfer
// wait for GPCs to all complete
mov $r10 8 // DONE_BAR
call wait_doneo
// wait for strand xfer to complete
call strand_wait
// post-op
bra $p1 ctx_xfer_post
mov $r10 12 // DONE_UNK12
call wait_donez
mov $r1 0xa10
shl b32 $r1 6
mov $r2 5
iowr I[$r1] $r2 // MEM_CMD
ctx_xfer_post_save_wait:
iord $r2 I[$r1]
or $r2 $r2
bra ne ctx_xfer_post_save_wait
bra $p2 ctx_xfer_done
ctx_xfer_post:
mov $r15 2
call ctx_4170s
clear b32 $r15
call ctx_86c
call strand_post
call ctx_4170w
clear b32 $r15
call ctx_4170s
bra not $p1 ctx_xfer_no_post_mmio
ld b32 $r1 D[$r0 + chan_mmio_count]
or $r1 $r1
bra e ctx_xfer_no_post_mmio
call ctx_mmio_exec
ctx_xfer_no_post_mmio:
call ctx_4160c
ctx_xfer_done:
ret
.align 256
uint32_t nvc0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x000000c0,
0x012c0090,
0x000000c1,
0x01300090,
0x000000c3,
0x012c0090,
0x000000c4,
0x012c0090,
0x000000c8,
0x012c0090,
0x000000ce,
0x012c0090,
0x00000000,
0x0417e91c,
0x04400204,
0x28404004,
0x00404044,
0x34404094,
0x184040d0,
0x004040f8,
0x08404130,
0x08404150,
0x04404164,
0x08404174,
0x1c404200,
0x34404404,
0x0c404460,
0x00404480,
0x00404498,
0x0c404604,
0x7c404618,
0x50404698,
0x044046f0,
0x54404700,
0x00405800,
0x08405830,
0x00405854,
0x0c405870,
0x04405a00,
0x00405a18,
0x00406020,
0x0c406028,
0x044064a8,
0x044064b4,
0x00407804,
0x1440780c,
0x004078bc,
0x18408000,
0x00408064,
0x08408800,
0x0c408900,
0x00408980,
0x044064c0,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
uint32_t nvc0_grhub_code[] = {
0x03090ef5,
0x9800d898,
0x86f001d9,
0x0489b808,
0xf00c1bf4,
0x21f502f7,
0x00f802ec,
0xb60798c4,
0x8dbb0384,
0x0880b600,
0x80008e80,
0x90b6018f,
0x0f94f001,
0xf801d980,
0x0131f400,
0x9800d898,
0x89b801d9,
0x210bf404,
0xb60789c4,
0x9dbb0394,
0x0890b600,
0x98009e98,
0x80b6019f,
0x0f84f001,
0xf400d880,
0x00f80132,
0x0728b7f1,
0xb906b4b6,
0xc9f002ec,
0x00bcd01f,
0xc800bccf,
0x1bf41fcc,
0x06a7f0fa,
0x010321f5,
0xf840bfcf,
0x28b7f100,
0x06b4b607,
0xb980bfd0,
0xc9f002ec,
0x1ec9f01f,
0xcf00bcd0,
0xccc800bc,
0xfa1bf41f,
0x87f100f8,
0x84b60430,
0x1ff9f006,
0xf8008fd0,
0x3087f100,
0x0684b604,
0xf80080d0,
0x3c87f100,
0x0684b608,
0x99f094bd,
0x0089d000,
0x081887f1,
0xd00684b6,
0x87f1008a,
0x84b60400,
0x0088cf06,
0xf4888aff,
0x87f1f31b,
0x84b6085c,
0xf094bd06,
0x89d00099,
0xf100f800,
0xb6083c87,
0x94bd0684,
0xd00099f0,
0x87f10089,
0x84b60818,
0x008ad006,
0x040087f1,
0xcf0684b6,
0x8aff0088,
0xf30bf488,
0x085c87f1,
0xbd0684b6,
0x0099f094,
0xf80089d0,
0x9894bd00,
0x85b600e8,
0x0180b61a,
0xbb0284b6,
0xe0b60098,
0x04efb804,
0xb9eb1bf4,
0x00f8029f,
0x083c87f1,
0xbd0684b6,
0x0199f094,
0xf10089d0,
0xb6071087,
0x94bd0684,
0xf405bbfd,
0x8bd0090b,
0x0099f000,
0xf405eefd,
0x8ed00c0b,
0xc08fd080,
0xb70199f0,
0xc8010080,
0xb4b600ab,
0x0cb9f010,
0xb601aec8,
0xbefd11e4,
0x008bd005,
0xf0008ecf,
0x0bf41fe4,
0x00ce98fa,
0xd005e9fd,
0xc0b6c08e,
0x04cdb804,
0xc8e81bf4,
0x1bf402ab,
0x008bcf18,
0xb01fb4f0,
0x1bf410b4,
0x02a7f0f7,
0xf4c921f4,
0xabc81b0e,
0x10b4b600,
0xf00cb9f0,
0x8bd012b9,
0x008bcf00,
0xf412bbc8,
0x87f1fa1b,
0x84b6085c,
0xf094bd06,
0x89d00199,
0xf900f800,
0x02a7f0a0,
0xfcc921f4,
0xf100f8a0,
0xf04afc87,
0x97f00283,
0x0089d00c,
0x020721f5,
0x87f100f8,
0x83f04afc,
0x0d97f002,
0xf50089d0,
0xf8020721,
0xfca7f100,
0x02a3f04f,
0x0500aba2,
0xd00fc7f0,
0xc7f000ac,
0x00bcd00b,
0x020721f5,
0xf000aed0,
0xbcd00ac7,
0x0721f500,
0xf100f802,
0xb6083c87,
0x94bd0684,
0xd00399f0,
0x21f50089,
0xe7f00213,
0x3921f503,
0xfca7f102,
0x02a3f046,
0x0400aba0,
0xf040a0d0,
0xbcd001c7,
0x0721f500,
0x010c9202,
0xf000acd0,
0xbcd002c7,
0x0721f500,
0x2621f502,
0x8087f102,
0x0684b608,
0xb70089cf,
0x95220080,
0x8ed008fe,
0x408ed000,
0xb6808acf,
0xa0b606a5,
0x00eabb01,
0xb60480b6,
0x1bf40192,
0x08e4b6e8,
0xf1f2efbc,
0xb6085c87,
0x94bd0684,
0xd00399f0,
0x00f80089,
0xe7f1e0f9,
0xe4b60814,
0x00efd006,
0x0c1ce7f1,
0xf006e4b6,
0xefd001f7,
0xf8e0fc00,
0xfe04bd00,
0x07fe0004,
0x0017f100,
0x0227f012,
0xf10012d0,
0xfe05b917,
0x17f10010,
0x10d00400,
0x0437f1c0,
0x0634b604,
0x200327f1,
0xf10032d0,
0xd0200427,
0x27f10132,
0x32d0200b,
0x0c27f102,
0x0732d020,
0x0c2427f1,
0xb90624b6,
0x23d00003,
0x0427f100,
0x0023f087,
0xb70012d0,
0xf0010012,
0x12d00427,
0x1031f400,
0x9604e7f1,
0xf440e3f0,
0xf1c76821,
0x01018090,
0x801ff4f0,
0x17f0000f,
0x041fbb01,
0xf10112b6,
0xb6040c27,
0x21d00624,
0x4021d000,
0x080027f1,
0xcf0624b6,
0xf7f00022,
0x08f0b654,
0xb800f398,
0x0bf40432,
0x0034b00b,
0xf8f11bf4,
0x0017f100,
0x02fe5801,
0xf003ff58,
0x0e8000e3,
0x150f8014,
0x013d21f5,
0x070037f1,
0x950634b6,
0x34d00814,
0x4034d000,
0x130030b7,
0xb6001fbb,
0x3fd002f5,
0x0815b600,
0xb60110b6,
0x1fb90814,
0x6321f502,
0x001fbb02,
0xf1000398,
0xf0200047,
0x4ea05043,
0x1fb90804,
0x8d21f402,
0x08004ea0,
0xf4022fb9,
0x4ea08d21,
0xf4bd010c,
0xa08d21f4,
0xf401044e,
0x4ea08d21,
0xf7f00100,
0x8d21f402,
0x08004ea0,
0xc86821f4,
0x0bf41fff,
0x044ea0fa,
0x6821f408,
0xb7001fbb,
0xb6800040,
0x1bf40132,
0x0027f1b4,
0x0624b608,
0xb74021d0,
0xbd080020,
0x1f19f014,
0xf40021d0,
0x28f40031,
0x08d7f000,
0xf43921f4,
0xe4b1f401,
0x1bf54001,
0x87f100d1,
0x84b6083c,
0xf094bd06,
0x89d00499,
0x0017f100,
0x0614b60b,
0xcf4012cf,
0x13c80011,
0x7e0bf41f,
0xf41f23c8,
0x20f95a0b,
0xf10212b9,
0xb6083c87,
0x94bd0684,
0xd00799f0,
0x32f40089,
0x0231f401,
0x082921f5,
0x085c87f1,
0xbd0684b6,
0x0799f094,
0xfc0089d0,
0x3c87f120,
0x0684b608,
0x99f094bd,
0x0089d006,
0xf50131f4,
0xf1082921,
0xb6085c87,
0x94bd0684,
0xd00699f0,
0x0ef40089,
0xb920f931,
0x32f40212,
0x0232f401,
0x082921f5,
0x17f120fc,
0x14b60b00,
0x0012d006,
0xc8130ef4,
0x0bf41f23,
0x0131f40d,
0xf50232f4,
0xf1082921,
0xb60b0c17,
0x27f00614,
0x0012d001,
0x085c87f1,
0xbd0684b6,
0x0499f094,
0xf50089d0,
0xb0ff200e,
0x1bf401e4,
0x02f2b90d,
0x07b521f5,
0xb0420ef4,
0x1bf402e4,
0x3c87f12e,
0x0684b608,
0x99f094bd,
0x0089d007,
0xf40132f4,
0x21f50232,
0x87f10829,
0x84b6085c,
0xf094bd06,
0x89d00799,
0x110ef400,
0xf010ef94,
0x21f501f5,
0x0ef502ec,
0x17f1fed1,
0x14b60820,
0xf024bd06,
0x12d01f29,
0xbe0ef500,
0xfe80f9fe,
0x80f90188,
0xa0f990f9,
0xd0f9b0f9,
0xf0f9e0f9,
0xc4800acf,
0x0bf404ab,
0x00b7f11d,
0x08d7f019,
0xcf40becf,
0x21f400bf,
0x00b0b704,
0x01e7f004,
0xe400bed0,
0xf40100ab,
0xd7f00d0b,
0x01e7f108,
0x0421f440,
0x0104b7f1,
0xabffb0bd,
0x0d0bf4b4,
0x0c1ca7f1,
0xd006a4b6,
0x0ad000ab,
0xfcf0fc40,
0xfcd0fce0,
0xfca0fcb0,
0xfe80fc90,
0x80fc0088,
0xf80032f4,
0x60e7f101,
0x40e3f041,
0xf401f7f0,
0x21f48d21,
0x04ffc868,
0xf8fa0bf4,
0x60e7f100,
0x40e3f041,
0x21f4f4bd,
0xf100f88d,
0xf04170e7,
0xf5f040e3,
0x8d21f410,
0xe7f100f8,
0xe3f04170,
0x6821f440,
0xf410f4f0,
0x00f8f31b,
0x0614e7f1,
0xf106e4b6,
0xd00270f7,
0xf7f000ef,
0x01f2b608,
0xf1fd1bf4,
0xd00770f7,
0x00f800ef,
0x086ce7f1,
0xd006e4b6,
0xe7f100ef,
0xe3f08a14,
0x8d21f440,
0xa86ce7f1,
0xf441e3f0,
0x00f88d21,
0x083c87f1,
0xbd0684b6,
0x0599f094,
0xf00089d0,
0x21f40ca7,
0x2417f1c9,
0x0614b60a,
0xf10010d0,
0xb60b0037,
0x32d00634,
0x0c17f140,
0x0614b60a,
0xd00747f0,
0x14d00012,
0x4014cf40,
0xf41f44f0,
0x32d0fa1b,
0x000bfe00,
0xb61f2af0,
0x20b60424,
0x3c87f102,
0x0684b608,
0x99f094bd,
0x0089d008,
0x0a0417f1,
0xd00614b6,
0x17f10012,
0x14b60a20,
0x0227f006,
0x800023f1,
0xf00012d0,
0x27f11017,
0x23f00300,
0x0512fa02,
0x87f103f8,
0x84b6085c,
0xf094bd06,
0x89d00899,
0xc1019800,
0x981814b6,
0x25b6c002,
0x0512fd08,
0xf1160180,
0xb6083c87,
0x94bd0684,
0xd00999f0,
0x27f10089,
0x24b60a04,
0x0021d006,
0xf10127f0,
0xb60a2017,
0x12d00614,
0x0017f100,
0x0613f002,
0xf80501fa,
0x5c87f103,
0x0684b608,
0x99f094bd,
0x0089d009,
0x085c87f1,
0xbd0684b6,
0x0599f094,
0xf80089d0,
0x3121f500,
0xb821f506,
0x0ca7f006,
0xf1c921f4,
0xb60a1017,
0x27f00614,
0x0012d005,
0xfd0012cf,
0x1bf40522,
0x4921f5fa,
0x9800f806,
0x27f18103,
0x24b60a04,
0x0023d006,
0x34c434bd,
0x0f1bf4ff,
0x030057f1,
0xfa0653f0,
0x03f80535,
0x98c04e98,
0x21f4c14f,
0x0830b68d,
0xf40112b6,
0x0398df1b,
0x0023d016,
0xf1800080,
0xf0020017,
0x01fa0613,
0xf803f806,
0x0611f400,
0xf01102f4,
0x21f510f7,
0x21f50698,
0x11f40631,
0x02f7f01c,
0x065721f5,
0x066621f5,
0x067821f5,
0x21f5f4bd,
0x21f50657,
0x019806b8,
0x1427f116,
0x0624b604,
0xf10020d0,
0xf0a500e7,
0x1fb941e3,
0x8d21f402,
0xf004e0b6,
0x2cf001fc,
0x0124b602,
0xf405f2fd,
0x17f18d21,
0x13f04afc,
0x0c27f002,
0xf50012d0,
0xf1020721,
0xf047fc27,
0x20d00223,
0x012cf000,
0xd00320b6,
0xacf00012,
0x06a5f001,
0x9800b7f0,
0x0d98140c,
0x00e7f015,
0x015c21f5,
0xf508a7f0,
0xf5010321,
0xf4020721,
0xa7f02201,
0xc921f40c,
0x0a1017f1,
0xf00614b6,
0x12d00527,
0x0012cf00,
0xf40522fd,
0x02f4fa1b,
0x02f7f032,
0x065721f5,
0x21f5f4bd,
0x21f50698,
0x21f50226,
0xf4bd0666,
0x065721f5,
0x981011f4,
0x11fd8001,
0x070bf405,
0x07df21f5,
0x064921f5,
0x000000f8,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment