linux/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c

/*
 * Copyright 2009 Marcin Kościelnicki
 *
 * 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.
 */

#define CP_FLAG_CLEAR
#define CP_FLAG_SET
#define CP_FLAG_SWAP_DIRECTION
#define CP_FLAG_SWAP_DIRECTION_LOAD
#define CP_FLAG_SWAP_DIRECTION_SAVE
#define CP_FLAG_UNK01
#define CP_FLAG_UNK01_CLEAR
#define CP_FLAG_UNK01_SET
#define CP_FLAG_UNK03
#define CP_FLAG_UNK03_CLEAR
#define CP_FLAG_UNK03_SET
#define CP_FLAG_USER_SAVE
#define CP_FLAG_USER_SAVE_NOT_PENDING
#define CP_FLAG_USER_SAVE_PENDING
#define CP_FLAG_USER_LOAD
#define CP_FLAG_USER_LOAD_NOT_PENDING
#define CP_FLAG_USER_LOAD_PENDING
#define CP_FLAG_UNK0B
#define CP_FLAG_UNK0B_CLEAR
#define CP_FLAG_UNK0B_SET
#define CP_FLAG_XFER_SWITCH
#define CP_FLAG_XFER_SWITCH_DISABLE
#define CP_FLAG_XFER_SWITCH_ENABLE
#define CP_FLAG_STATE
#define CP_FLAG_STATE_STOPPED
#define CP_FLAG_STATE_RUNNING
#define CP_FLAG_UNK1D
#define CP_FLAG_UNK1D_CLEAR
#define CP_FLAG_UNK1D_SET
#define CP_FLAG_UNK20
#define CP_FLAG_UNK20_CLEAR
#define CP_FLAG_UNK20_SET
#define CP_FLAG_STATUS
#define CP_FLAG_STATUS_BUSY
#define CP_FLAG_STATUS_IDLE
#define CP_FLAG_AUTO_SAVE
#define CP_FLAG_AUTO_SAVE_NOT_PENDING
#define CP_FLAG_AUTO_SAVE_PENDING
#define CP_FLAG_AUTO_LOAD
#define CP_FLAG_AUTO_LOAD_NOT_PENDING
#define CP_FLAG_AUTO_LOAD_PENDING
#define CP_FLAG_NEWCTX
#define CP_FLAG_NEWCTX_BUSY
#define CP_FLAG_NEWCTX_DONE
#define CP_FLAG_XFER
#define CP_FLAG_XFER_IDLE
#define CP_FLAG_XFER_BUSY
#define CP_FLAG_ALWAYS
#define CP_FLAG_ALWAYS_FALSE
#define CP_FLAG_ALWAYS_TRUE
#define CP_FLAG_INTR
#define CP_FLAG_INTR_NOT_PENDING
#define CP_FLAG_INTR_PENDING

#define CP_CTX
#define CP_CTX_COUNT
#define CP_CTX_COUNT_SHIFT
#define CP_CTX_REG
#define CP_LOAD_SR
#define CP_LOAD_SR_VALUE
#define CP_BRA
#define CP_BRA_IP
#define CP_BRA_IP_SHIFT
#define CP_BRA_IF_CLEAR
#define CP_BRA_FLAG
#define CP_WAIT
#define CP_WAIT_SET
#define CP_WAIT_FLAG
#define CP_SET
#define CP_SET_1
#define CP_SET_FLAG
#define CP_NEWCTX
#define CP_NEXT_TO_SWAP
#define CP_SET_CONTEXT_POINTER
#define CP_SET_XFER_POINTER
#define CP_ENABLE
#define CP_END
#define CP_NEXT_TO_CURRENT
#define CP_DISABLE1
#define CP_DISABLE2
#define CP_XFER_1
#define CP_XFER_2
#define CP_SEEK_1
#define CP_SEEK_2

#include "ctxnv40.h"
#include "nv50.h"

#include <subdev/fb.h>

#define IS_NVA3F(x)
#define IS_NVAAF(x)

/*
 * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
 * the GPU itself that does context-switching, but it needs a special
 * microcode to do it. And it's the driver's task to supply this microcode,
 * further known as ctxprog, as well as the initial context values, known
 * as ctxvals.
 *
 * Without ctxprog, you cannot switch contexts. Not even in software, since
 * the majority of context [xfer strands] isn't accessible directly. You're
 * stuck with a single channel, and you also suffer all the problems resulting
 * from missing ctxvals, since you cannot load them.
 *
 * Without ctxvals, you're stuck with PGRAPH's default context. It's enough to
 * run 2d operations, but trying to utilise 3d or CUDA will just lock you up,
 * since you don't have... some sort of needed setup.
 *
 * Nouveau will just disable acceleration if not given ctxprog + ctxvals, since
 * it's too much hassle to handle no-ctxprog as a special case.
 */

/*
 * How ctxprogs work.
 *
 * The ctxprog is written in its own kind of microcode, with very small and
 * crappy set of available commands. You upload it to a small [512 insns]
 * area of memory on PGRAPH, and it'll be run when PFIFO wants PGRAPH to
 * switch channel. or when the driver explicitely requests it. Stuff visible
 * to ctxprog consists of: PGRAPH MMIO registers, PGRAPH context strands,
 * the per-channel context save area in VRAM [known as ctxvals or grctx],
 * 4 flags registers, a scratch register, two grctx pointers, plus many
 * random poorly-understood details.
 *
 * When ctxprog runs, it's supposed to check what operations are asked of it,
 * save old context if requested, optionally reset PGRAPH and switch to the
 * new channel, and load the new context. Context consists of three major
 * parts: subset of MMIO registers and two "xfer areas".
 */

/* TODO:
 *  - document unimplemented bits compared to nvidia
 *  - NVAx: make a TP subroutine, use it.
 *  - use 0x4008fc instead of 0x1540?
 */

enum cp_label {};

static void nv50_gr_construct_mmio(struct nvkm_grctx *ctx);
static void nv50_gr_construct_xfer1(struct nvkm_grctx *ctx);
static void nv50_gr_construct_xfer2(struct nvkm_grctx *ctx);

/* Main function: construct the ctxprog skeleton, call the other functions. */

static int
nv50_grctx_generate(struct nvkm_grctx *ctx)
{}

void
nv50_grctx_fill(struct nvkm_device *device, struct nvkm_gpuobj *mem)
{}

int
nv50_grctx_init(struct nvkm_device *device, u32 *size)
{}

/*
 * Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which
 * registers to save/restore and the default values for them.
 */

static void
nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx);

static void
nv50_gr_construct_mmio(struct nvkm_grctx *ctx)
{}

static void
dd_emit(struct nvkm_grctx *ctx, int num, u32 val) {}

static void
nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx)
{}

/*
 * xfer areas. These are a pain.
 *
 * There are 2 xfer areas: the first one is big and contains all sorts of
 * stuff, the second is small and contains some per-TP context.
 *
 * Each area is split into 8 "strands". The areas, when saved to grctx,
 * are made of 8-word blocks. Each block contains a single word from
 * each strand. The strands are independent of each other, their
 * addresses are unrelated to each other, and data in them is closely
 * packed together. The strand layout varies a bit between cards: here
 * and there, a single word is thrown out in the middle and the whole
 * strand is offset by a bit from corresponding one on another chipset.
 * For this reason, addresses of stuff in strands are almost useless.
 * Knowing sequence of stuff and size of gaps between them is much more
 * useful, and that's how we build the strands in our generator.
 *
 * NVA0 takes this mess to a whole new level by cutting the old strands
 * into a few dozen pieces [known as genes], rearranging them randomly,
 * and putting them back together to make new strands. Hopefully these
 * genes correspond more or less directly to the same PGRAPH subunits
 * as in 400040 register.
 *
 * The most common value in default context is 0, and when the genes
 * are separated by 0's, gene bounduaries are quite speculative...
 * some of them can be clearly deduced, others can be guessed, and yet
 * others won't be resolved without figuring out the real meaning of
 * given ctxval. For the same reason, ending point of each strand
 * is unknown. Except for strand 0, which is the longest strand and
 * its end corresponds to end of the whole xfer.
 *
 * An unsolved mystery is the seek instruction: it takes an argument
 * in bits 8-18, and that argument is clearly the place in strands to
 * seek to... but the offsets don't seem to correspond to offsets as
 * seen in grctx. Perhaps there's another, real, not randomly-changing
 * addressing in strands, and the xfer insn just happens to skip over
 * the unused bits? NV10-NV30 PIPE comes to mind...
 *
 * As far as I know, there's no way to access the xfer areas directly
 * without the help of ctxprog.
 */

static void
xf_emit(struct nvkm_grctx *ctx, int num, u32 val) {}

/* Gene declarations... */

static void nv50_gr_construct_gene_dispatch(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_m2mf(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_ccache(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_unk10xx(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_unk14xx(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_zcull(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_clipid(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_unk24xx(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_vfetch(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_eng2d(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_csched(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_unk1cxx(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_strmout(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_unk34xx(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_ropm1(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_ropm2(struct nvkm_grctx *ctx);
static void nv50_gr_construct_gene_ropc(struct nvkm_grctx *ctx);
static void nv50_gr_construct_xfer_tp(struct nvkm_grctx *ctx);

static void
nv50_gr_construct_xfer1(struct nvkm_grctx *ctx)
{}

/*
 * non-trivial demagiced parts of ctx init go here
 */

static void
nv50_gr_construct_gene_dispatch(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_m2mf(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_ccache(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_unk10xx(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_unk34xx(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_unk14xx(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_zcull(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_clipid(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_unk24xx(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_vfetch(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_eng2d(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_csched(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_unk1cxx(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_strmout(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_ropm1(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_ropm2(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_gene_ropc(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_xfer_unk84xx(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_xfer_tprop(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_xfer_tex(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_xfer_unk8cxx(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_xfer_tp(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_xfer_mpc(struct nvkm_grctx *ctx)
{}

static void
nv50_gr_construct_xfer2(struct nvkm_grctx *ctx)
{}