summaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2011-05-16 03:53:27 +0200
committerDave Airlie <airlied@redhat.com>2011-05-16 03:53:27 +0200
commit46f2b6073430e14561f3aea1cee19b35223e0c04 (patch)
tree30de66b80dcf23c3287384fa6b668ee4cd985d1a /drivers/gpu
parentMerge remote branch 'keithp/drm-intel-next' of /ssd/git/drm-next into drm-cor... (diff)
parentdrm/nouveau: make cursor_set implementation consistent with other drivers (diff)
downloadlinux-46f2b6073430e14561f3aea1cee19b35223e0c04.tar.xz
linux-46f2b6073430e14561f3aea1cee19b35223e0c04.zip
Merge remote branch 'nouveau/drm-nouveau-next' of /ssd/git/drm-nouveau-next into drm-core-next
* 'nouveau/drm-nouveau-next' of /ssd/git/drm-nouveau-next: (55 commits) drm/nouveau: make cursor_set implementation consistent with other drivers drm/nva3/clk: better pll calculation when no fractional fb div available drm/nouveau/pm: translate ramcfg strap through ram restrict table drm/nva3/pm: allow use of divisor 16 drm/nvc0/pm: parse clock for pll 0x0a (0x137020) from perf table drm/nvc0/pm: correct core/mem/shader perflvl parsing drm/nouveau/pm: remove memtiming support check when assigning to perflvl drm/nva3: support for memory timing map table drm/nouveau: Associate memtimings with performance levels on cards <= nv98 drm/nva3/pm: initial pass at set_clock() hook drm/nvc0/gr: calculate some more of our magic numbers drm/nv50: respect LVDS link count from EDID on SPWG panels drm/nouveau: recognise DCB connector type 0x41 as LVDS drm/nouveau: fix uninitialised variable warning drm/nouveau: Fix a crash at card takedown for NV40 and older cards drm/nouveau: Free nv04 instmem ramin heap at card takedown drm/nva3: somewhat improve clock reporting drm/nouveau: pull refclk from vbios on limits 0x40 boards drm/nv40/gr: oops, fix random bits getting set in engine obj drm/nv50: improve nv50_pm_get_clock() ...
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/Makefile2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c20
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c25
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h208
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.h10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c68
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c118
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c92
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c217
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vm.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_volt.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c9
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c383
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c212
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c510
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c323
-rw-r--r--drivers/gpu/drm/nouveau/nv40_mpeg.c311
-rw-r--r--drivers/gpu/drm/nouveau/nv50_calc.c68
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c13
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c18
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c442
-rw-r--r--drivers/gpu/drm/nouveau/nv50_grctx.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv50_mpeg.c256
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv50_vm.c12
-rw-r--r--drivers/gpu/drm/nouveau/nv84_crypt.c135
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.c226
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.fuc870
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.fuc.h534
-rw-r--r--drivers/gpu/drm/nouveau/nva3_pm.c169
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_copy.c243
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_copy.fuc.h527
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fifo.c142
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c600
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.h29
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_grctx.c20
44 files changed, 5071 insertions, 1837 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index e12c97fd8db8..0583677e4581 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -20,6 +20,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv40_graph.o nv50_graph.o nvc0_graph.o \
nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
nv84_crypt.o \
+ nva3_copy.o nvc0_copy.o \
+ nv40_mpeg.o nv50_mpeg.o \
nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 90aef64b76f2..729d5fd7c88d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -5049,11 +5049,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
pll_lim->vco1.max_n = record[11];
pll_lim->min_p = record[12];
pll_lim->max_p = record[13];
- /* where did this go to?? */
- if ((entry[0] & 0xf0) == 0x80)
- pll_lim->refclk = 27000;
- else
- pll_lim->refclk = 100000;
+ pll_lim->refclk = ROM16(entry[9]) * 1000;
}
/*
@@ -6035,6 +6031,7 @@ parse_dcb_connector_table(struct nvbios *bios)
case DCB_CONNECTOR_DVI_I:
case DCB_CONNECTOR_DVI_D:
case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_LVDS_SPWG:
case DCB_CONNECTOR_DP:
case DCB_CONNECTOR_eDP:
case DCB_CONNECTOR_HDMI_0:
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 8a54fa7edf5c..050c314119df 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -82,6 +82,7 @@ enum dcb_connector_type {
DCB_CONNECTOR_DVI_I = 0x30,
DCB_CONNECTOR_DVI_D = 0x31,
DCB_CONNECTOR_LVDS = 0x40,
+ DCB_CONNECTOR_LVDS_SPWG = 0x41,
DCB_CONNECTOR_DP = 0x46,
DCB_CONNECTOR_eDP = 0x47,
DCB_CONNECTOR_HDMI_0 = 0x60,
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 4cea35c57d15..a7583a8ddb01 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -268,9 +268,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
unsigned long flags;
+ int i;
/* decrement the refcount, and we're done if there's still refs */
if (likely(!atomic_dec_and_test(&chan->users))) {
@@ -294,19 +293,12 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
/* boot it off the hardware */
pfifo->reassign(dev, false);
- /* We want to give pgraph a chance to idle and get rid of all
- * potential errors. We need to do this without the context
- * switch lock held, otherwise the irq handler is unable to
- * process them.
- */
- if (pgraph->channel(dev) == chan)
- nouveau_wait_for_idle(dev);
-
/* destroy the engine specific contexts */
pfifo->destroy_context(chan);
- pgraph->destroy_context(chan);
- if (pcrypt->destroy_context)
- pcrypt->destroy_context(chan);
+ for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+ if (chan->engctx[i])
+ dev_priv->eng[i]->context_del(chan, i);
+ }
pfifo->reassign(dev, true);
@@ -414,7 +406,7 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
- if (dev_priv->engine.graph.accel_blocked)
+ if (!dev_priv->eng[NVOBJ_ENGINE_GR])
return -ENODEV;
if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 7ae151109a66..1595d0b6e815 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -442,7 +442,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
}
/* LVDS always needs gpu scaling */
- if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS &&
+ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
value == DRM_MODE_SCALE_NONE)
return -EINVAL;
@@ -650,6 +650,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
+ nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG ||
nv_connector->dcb->type == DCB_CONNECTOR_eDP)
ret += nouveau_connector_scaler_modes_add(connector);
@@ -810,6 +811,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
type = DRM_MODE_CONNECTOR_HDMIA;
break;
case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_LVDS_SPWG:
type = DRM_MODE_CONNECTOR_LVDS;
funcs = &nouveau_connector_funcs_lvds;
break;
@@ -838,7 +840,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
/* Check if we need dithering enabled */
- if (dcb->type == DCB_CONNECTOR_LVDS) {
+ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
bool dummy, is_24bit = false;
ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);
@@ -883,7 +885,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
nv_connector->use_dithering ?
DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
- if (dcb->type != DCB_CONNECTOR_LVDS) {
+ if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) {
if (dev_priv->card_type >= NV_50)
connector->polled = DRM_CONNECTOR_POLL_HPD;
else
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 764c15d537ba..eb514ea29377 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -276,7 +276,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct nouveau_fence *fence;
int ret;
- if (dev_priv->engine.graph.accel_blocked)
+ if (!dev_priv->channel)
return -ENODEV;
s = kzalloc(sizeof(*s), GFP_KERNEL);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 155ebdcbf06f..02c6f37d8bd7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -162,11 +162,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
struct drm_device *dev = pci_get_drvdata(pdev);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan;
struct drm_crtc *crtc;
- int ret, i;
+ int ret, i, e;
if (pm_state.event == PM_EVENT_PRETHAW)
return 0;
@@ -206,12 +205,17 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
nouveau_channel_idle(chan);
}
- pgraph->fifo_access(dev, false);
- nouveau_wait_for_idle(dev);
pfifo->reassign(dev, false);
pfifo->disable(dev);
pfifo->unload_context(dev);
- pgraph->unload_context(dev);
+
+ for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+ if (dev_priv->eng[e]) {
+ ret = dev_priv->eng[e]->fini(dev, e);
+ if (ret)
+ goto out_abort;
+ }
+ }
ret = pinstmem->suspend(dev);
if (ret) {
@@ -242,9 +246,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
out_abort:
NV_INFO(dev, "Re-enabling acceleration..\n");
+ for (e = e + 1; e < NVOBJ_ENGINE_NR; e++) {
+ if (dev_priv->eng[e])
+ dev_priv->eng[e]->init(dev, e);
+ }
pfifo->enable(dev);
pfifo->reassign(dev, true);
- pgraph->fifo_access(dev, true);
return ret;
}
@@ -299,8 +306,10 @@ nouveau_pci_resume(struct pci_dev *pdev)
engine->mc.init(dev);
engine->timer.init(dev);
engine->fb.init(dev);
- engine->graph.init(dev);
- engine->crypt.init(dev);
+ for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+ if (dev_priv->eng[i])
+ dev_priv->eng[i]->init(dev, i);
+ }
engine->fifo.init(dev);
nouveau_irq_postinstall(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index a76514a209b3..9c56331941e2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -150,13 +150,12 @@ enum nouveau_flags {
#define NVOBJ_ENGINE_SW 0
#define NVOBJ_ENGINE_GR 1
-#define NVOBJ_ENGINE_PPP 2
-#define NVOBJ_ENGINE_COPY 3
-#define NVOBJ_ENGINE_VP 4
-#define NVOBJ_ENGINE_CRYPT 5
-#define NVOBJ_ENGINE_BSP 6
-#define NVOBJ_ENGINE_DISPLAY 0xcafe0001
-#define NVOBJ_ENGINE_INT 0xdeadbeef
+#define NVOBJ_ENGINE_CRYPT 2
+#define NVOBJ_ENGINE_COPY0 3
+#define NVOBJ_ENGINE_COPY1 4
+#define NVOBJ_ENGINE_MPEG 5
+#define NVOBJ_ENGINE_DISPLAY 15
+#define NVOBJ_ENGINE_NR 16
#define NVOBJ_FLAG_DONT_MAP (1 << 0)
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
@@ -245,11 +244,8 @@ struct nouveau_channel {
struct nouveau_gpuobj *cache;
void *fifo_priv;
- /* PGRAPH context */
- /* XXX may be merge 2 pointers as private data ??? */
- struct nouveau_gpuobj *ramin_grctx;
- struct nouveau_gpuobj *crypt_ctx;
- void *pgraph_ctx;
+ /* Execution engine contexts */
+ void *engctx[NVOBJ_ENGINE_NR];
/* NV50 VM */
struct nouveau_vm *vm;
@@ -298,6 +294,18 @@ struct nouveau_channel {
} debugfs;
};
+struct nouveau_exec_engine {
+ void (*destroy)(struct drm_device *, int engine);
+ int (*init)(struct drm_device *, int engine);
+ int (*fini)(struct drm_device *, int engine);
+ int (*context_new)(struct nouveau_channel *, int engine);
+ void (*context_del)(struct nouveau_channel *, int engine);
+ int (*object_new)(struct nouveau_channel *, int engine,
+ u32 handle, u16 class);
+ void (*set_tile_region)(struct drm_device *dev, int i);
+ void (*tlb_flush)(struct drm_device *, int engine);
+};
+
struct nouveau_instmem_engine {
void *priv;
@@ -364,30 +372,6 @@ struct nouveau_fifo_engine {
void (*tlb_flush)(struct drm_device *dev);
};
-struct nouveau_pgraph_engine {
- bool accel_blocked;
- bool registered;
- int grctx_size;
- void *priv;
-
- /* NV2x/NV3x context table (0x400780) */
- struct nouveau_gpuobj *ctx_table;
-
- int (*init)(struct drm_device *);
- void (*takedown)(struct drm_device *);
-
- void (*fifo_access)(struct drm_device *, bool);
-
- struct nouveau_channel *(*channel)(struct drm_device *);
- int (*create_context)(struct nouveau_channel *);
- void (*destroy_context)(struct nouveau_channel *);
- int (*load_context)(struct nouveau_channel *);
- int (*unload_context)(struct drm_device *);
- void (*tlb_flush)(struct drm_device *dev);
-
- void (*set_tile_region)(struct drm_device *dev, int i);
-};
-
struct nouveau_display_engine {
void *priv;
int (*early_init)(struct drm_device *);
@@ -426,6 +410,19 @@ struct nouveau_pm_voltage {
int nr_level;
};
+struct nouveau_pm_memtiming {
+ int id;
+ u32 reg_100220;
+ u32 reg_100224;
+ u32 reg_100228;
+ u32 reg_10022c;
+ u32 reg_100230;
+ u32 reg_100234;
+ u32 reg_100238;
+ u32 reg_10023c;
+ u32 reg_100240;
+};
+
#define NOUVEAU_PM_MAX_LEVEL 8
struct nouveau_pm_level {
struct device_attribute dev_attr;
@@ -436,11 +433,13 @@ struct nouveau_pm_level {
u32 memory;
u32 shader;
u32 unk05;
+ u32 unk0a;
u8 voltage;
u8 fanspeed;
u16 memscript;
+ struct nouveau_pm_memtiming *timing;
};
struct nouveau_pm_temp_sensor_constants {
@@ -457,17 +456,6 @@ struct nouveau_pm_threshold_temp {
s16 fan_boost;
};
-struct nouveau_pm_memtiming {
- u32 reg_100220;
- u32 reg_100224;
- u32 reg_100228;
- u32 reg_10022c;
- u32 reg_100230;
- u32 reg_100234;
- u32 reg_100238;
- u32 reg_10023c;
-};
-
struct nouveau_pm_memtimings {
bool supported;
struct nouveau_pm_memtiming *timing;
@@ -499,16 +487,6 @@ struct nouveau_pm_engine {
int (*temp_get)(struct drm_device *);
};
-struct nouveau_crypt_engine {
- bool registered;
-
- int (*init)(struct drm_device *);
- void (*takedown)(struct drm_device *);
- int (*create_context)(struct nouveau_channel *);
- void (*destroy_context)(struct nouveau_channel *);
- void (*tlb_flush)(struct drm_device *dev);
-};
-
struct nouveau_vram_engine {
int (*init)(struct drm_device *);
int (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
@@ -523,12 +501,10 @@ struct nouveau_engine {
struct nouveau_mc_engine mc;
struct nouveau_timer_engine timer;
struct nouveau_fb_engine fb;
- struct nouveau_pgraph_engine graph;
struct nouveau_fifo_engine fifo;
struct nouveau_display_engine display;
struct nouveau_gpio_engine gpio;
struct nouveau_pm_engine pm;
- struct nouveau_crypt_engine crypt;
struct nouveau_vram_engine vram;
};
@@ -637,6 +613,7 @@ struct drm_nouveau_private {
enum nouveau_card_type card_type;
/* exact chipset, derived from NV_PMC_BOOT_0 */
int chipset;
+ int stepping;
int flags;
void __iomem *mmio;
@@ -647,6 +624,7 @@ struct drm_nouveau_private {
u32 ramin_base;
bool ramin_available;
struct drm_mm ramin_heap;
+ struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
struct list_head gpuobj_list;
struct list_head classes;
@@ -745,10 +723,6 @@ struct drm_nouveau_private {
uint32_t crtc_owner;
uint32_t dac_users[4];
- struct nouveau_suspend_resume {
- uint32_t *ramin_copy;
- } susres;
-
struct backlight_device *backlight;
struct {
@@ -757,8 +731,6 @@ struct drm_nouveau_private {
struct nouveau_fbdev *nfbdev;
struct apertures_struct *apertures;
-
- bool powered_down;
};
static inline struct drm_nouveau_private *
@@ -883,17 +855,27 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan,
extern void nouveau_channel_idle(struct nouveau_channel *chan);
/* nouveau_object.c */
-#define NVOBJ_CLASS(d,c,e) do { \
+#define NVOBJ_ENGINE_ADD(d, e, p) do { \
+ struct drm_nouveau_private *dev_priv = (d)->dev_private; \
+ dev_priv->eng[NVOBJ_ENGINE_##e] = (p); \
+} while (0)
+
+#define NVOBJ_ENGINE_DEL(d, e) do { \
+ struct drm_nouveau_private *dev_priv = (d)->dev_private; \
+ dev_priv->eng[NVOBJ_ENGINE_##e] = NULL; \
+} while (0)
+
+#define NVOBJ_CLASS(d, c, e) do { \
int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e); \
if (ret) \
return ret; \
-} while(0)
+} while (0)
-#define NVOBJ_MTHD(d,c,m,e) do { \
+#define NVOBJ_MTHD(d, c, m, e) do { \
int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e)); \
if (ret) \
return ret; \
-} while(0)
+} while (0)
extern int nouveau_gpuobj_early_init(struct drm_device *);
extern int nouveau_gpuobj_init(struct drm_device *);
@@ -903,7 +885,7 @@ extern void nouveau_gpuobj_resume(struct drm_device *dev);
extern int nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng);
extern int nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd,
int (*exec)(struct nouveau_channel *,
- u32 class, u32 mthd, u32 data));
+ u32 class, u32 mthd, u32 data));
extern int nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32);
extern int nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32);
extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
@@ -1137,81 +1119,50 @@ extern int nvc0_fifo_load_context(struct nouveau_channel *);
extern int nvc0_fifo_unload_context(struct drm_device *);
/* nv04_graph.c */
-extern int nv04_graph_init(struct drm_device *);
-extern void nv04_graph_takedown(struct drm_device *);
+extern int nv04_graph_create(struct drm_device *);
extern void nv04_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv04_graph_channel(struct drm_device *);
-extern int nv04_graph_create_context(struct nouveau_channel *);
-extern void nv04_graph_destroy_context(struct nouveau_channel *);
-extern int nv04_graph_load_context(struct nouveau_channel *);
-extern int nv04_graph_unload_context(struct drm_device *);
+extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data);
extern struct nouveau_bitfield nv04_graph_nsource[];
/* nv10_graph.c */
-extern int nv10_graph_init(struct drm_device *);
-extern void nv10_graph_takedown(struct drm_device *);
+extern int nv10_graph_create(struct drm_device *);
extern struct nouveau_channel *nv10_graph_channel(struct drm_device *);
-extern int nv10_graph_create_context(struct nouveau_channel *);
-extern void nv10_graph_destroy_context(struct nouveau_channel *);
-extern int nv10_graph_load_context(struct nouveau_channel *);
-extern int nv10_graph_unload_context(struct drm_device *);
-extern void nv10_graph_set_tile_region(struct drm_device *dev, int i);
extern struct nouveau_bitfield nv10_graph_intr[];
extern struct nouveau_bitfield nv10_graph_nstatus[];
/* nv20_graph.c */
-extern int nv20_graph_create_context(struct nouveau_channel *);
-extern void nv20_graph_destroy_context(struct nouveau_channel *);
-extern int nv20_graph_load_context(struct nouveau_channel *);
-extern int nv20_graph_unload_context(struct drm_device *);
-extern int nv20_graph_init(struct drm_device *);
-extern void nv20_graph_takedown(struct drm_device *);
-extern int nv30_graph_init(struct drm_device *);
-extern void nv20_graph_set_tile_region(struct drm_device *dev, int i);
+extern int nv20_graph_create(struct drm_device *);
/* nv40_graph.c */
-extern int nv40_graph_init(struct drm_device *);
-extern void nv40_graph_takedown(struct drm_device *);
-extern struct nouveau_channel *nv40_graph_channel(struct drm_device *);
-extern int nv40_graph_create_context(struct nouveau_channel *);
-extern void nv40_graph_destroy_context(struct nouveau_channel *);
-extern int nv40_graph_load_context(struct nouveau_channel *);
-extern int nv40_graph_unload_context(struct drm_device *);
+extern int nv40_graph_create(struct drm_device *);
extern void nv40_grctx_init(struct nouveau_grctx *);
-extern void nv40_graph_set_tile_region(struct drm_device *dev, int i);
/* nv50_graph.c */
-extern int nv50_graph_init(struct drm_device *);
-extern void nv50_graph_takedown(struct drm_device *);
-extern void nv50_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv50_graph_channel(struct drm_device *);
-extern int nv50_graph_create_context(struct nouveau_channel *);
-extern void nv50_graph_destroy_context(struct nouveau_channel *);
-extern int nv50_graph_load_context(struct nouveau_channel *);
-extern int nv50_graph_unload_context(struct drm_device *);
+extern int nv50_graph_create(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
-extern void nv50_graph_tlb_flush(struct drm_device *dev);
-extern void nv84_graph_tlb_flush(struct drm_device *dev);
extern struct nouveau_enum nv50_data_error_names[];
+extern int nv50_graph_isr_chid(struct drm_device *dev, u64 inst);
/* nvc0_graph.c */
-extern int nvc0_graph_init(struct drm_device *);
-extern void nvc0_graph_takedown(struct drm_device *);
-extern void nvc0_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
-extern int nvc0_graph_create_context(struct nouveau_channel *);
-extern void nvc0_graph_destroy_context(struct nouveau_channel *);
-extern int nvc0_graph_load_context(struct nouveau_channel *);
-extern int nvc0_graph_unload_context(struct drm_device *);
+extern int nvc0_graph_create(struct drm_device *);
+extern int nvc0_graph_isr_chid(struct drm_device *dev, u64 inst);
/* nv84_crypt.c */
-extern int nv84_crypt_init(struct drm_device *dev);
-extern void nv84_crypt_fini(struct drm_device *dev);
-extern int nv84_crypt_create_context(struct nouveau_channel *);
-extern void nv84_crypt_destroy_context(struct nouveau_channel *);
-extern void nv84_crypt_tlb_flush(struct drm_device *dev);
+extern int nv84_crypt_create(struct drm_device *);
+
+/* nva3_copy.c */
+extern int nva3_copy_create(struct drm_device *dev);
+
+/* nvc0_copy.c */
+extern int nvc0_copy_create(struct drm_device *dev, int engine);
+
+/* nv40_mpeg.c */
+extern int nv40_mpeg_create(struct drm_device *dev);
+
+/* nv50_mpeg.c */
+extern int nv50_mpeg_create(struct drm_device *dev);
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
@@ -1402,8 +1353,8 @@ bool nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
/* nv50_calc. */
int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
int *N1, int *M1, int *N2, int *M2, int *P);
-int nv50_calc_pll2(struct drm_device *, struct pll_lims *,
- int clk, int *N, int *fN, int *M, int *P);
+int nva3_calc_pll(struct drm_device *, struct pll_lims *,
+ int clk, int *N, int *fN, int *M, int *P);
#ifndef ioread32_native
#ifdef __BIG_ENDIAN
@@ -1579,6 +1530,13 @@ nv_match_device(struct drm_device *dev, unsigned device,
dev->pdev->subsystem_device == sub_device;
}
+static inline void *
+nv_engine(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ return (void *)dev_priv->eng[engine];
+}
+
/* returns 1 if device is one of the nv4x using the 0x4497 object class,
* helpful to determine a number of other hardware features
*/
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.h b/drivers/gpu/drm/nouveau/nouveau_grctx.h
index 4a8ad1307fa4..86c2e374e938 100644
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.h
+++ b/drivers/gpu/drm/nouveau/nouveau_grctx.h
@@ -87,10 +87,10 @@ _cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
(state ? 0 : CP_BRA_IF_CLEAR));
}
-#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
#ifdef CP_BRA_MOD
-#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
#endif
static inline void
@@ -98,14 +98,14 @@ _cp_wait(struct nouveau_grctx *ctx, int flag, int state)
{
cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
}
-#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
static inline void
_cp_set(struct nouveau_grctx *ctx, int flag, int state)
{
cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
}
-#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
static inline void
cp_pos(struct nouveau_grctx *ctx, int offset)
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 5045f8b921d6..2960f583dc38 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -51,8 +51,7 @@ nv10_mem_update_tile_region(struct drm_device *dev,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- int i = tile - dev_priv->tile.reg;
+ int i = tile - dev_priv->tile.reg, j;
unsigned long save;
nouveau_fence_unref(&tile->fence);
@@ -70,7 +69,10 @@ nv10_mem_update_tile_region(struct drm_device *dev,
nouveau_wait_for_idle(dev);
pfb->set_tile_region(dev, i);
- pgraph->set_tile_region(dev, i);
+ for (j = 0; j < NVOBJ_ENGINE_NR; j++) {
+ if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region)
+ dev_priv->eng[j]->set_tile_region(dev, i);
+ }
pfifo->cache_pull(dev, true);
pfifo->reassign(dev, true);
@@ -152,8 +154,6 @@ nouveau_mem_vram_fini(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- nouveau_bo_ref(NULL, &dev_priv->vga_ram);
-
ttm_bo_device_release(&dev_priv->ttm.bdev);
nouveau_ttm_global_release(dev_priv);
@@ -597,10 +597,10 @@ nouveau_mem_timing_init(struct drm_device *dev)
if (!memtimings->timing)
return;
- /* Get "some number" from the timing reg for NV_40
+ /* Get "some number" from the timing reg for NV_40 and NV_50
* Used in calculations later */
- if(dev_priv->card_type == NV_40) {
- magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24;
+ if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) {
+ magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
}
entry = mem + mem[1];
@@ -643,51 +643,68 @@ nouveau_mem_timing_init(struct drm_device *dev)
/* XXX: I don't trust the -1's and +1's... they must come
* from somewhere! */
timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
- tUNK_18 << 16 |
+ max(tUNK_18, (u8) 1) << 16 |
(tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
- if(dev_priv->chipset == 0xa8) {
+ if (dev_priv->chipset == 0xa8) {
timing->reg_100224 |= (tUNK_2 - 1);
} else {
timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
}
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
- if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) {
+ if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa)
timing->reg_100228 |= (tUNK_19 - 1) << 24;
- }
+ else
+ timing->reg_100228 |= magic_number << 24;
- if(dev_priv->card_type == NV_40) {
+ if (dev_priv->card_type == NV_40) {
/* NV40: don't know what the rest of the regs are..
* And don't need to know either */
- timing->reg_100228 |= 0x20200000 | magic_number << 24;
- } else if(dev_priv->card_type >= NV_50) {
- /* XXX: reg_10022c */
- timing->reg_10022c = tUNK_2 - 1;
+ timing->reg_100228 |= 0x20200000;
+ } else if (dev_priv->card_type >= NV_50) {
+ if (dev_priv->chipset < 0x98 ||
+ (dev_priv->chipset == 0x98 &&
+ dev_priv->stepping <= 0xa1)) {
+ timing->reg_10022c = (0x14 + tUNK_2) << 24 |
+ 0x16 << 16 |
+ (tUNK_2 - 1) << 8 |
+ (tUNK_2 - 1);
+ } else {
+ /* XXX: reg_10022c for recentish cards */
+ timing->reg_10022c = tUNK_2 - 1;
+ }
timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
tUNK_13 << 8 | tUNK_13);
timing->reg_100234 = (tRAS << 24 | tRC);
- timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+ timing->reg_100234 += max(tUNK_10, tUNK_11) << 16;
- if(dev_priv->chipset < 0xa3) {
+ if (dev_priv->chipset < 0x98 ||
+ (dev_priv->chipset == 0x98 &&
+ dev_priv->stepping <= 0xa1)) {
timing->reg_100234 |= (tUNK_2 + 2) << 8;
} else {
/* XXX: +6? */
timing->reg_100234 |= (tUNK_19 + 6) << 8;
}
- /* XXX; reg_100238, reg_10023c
- * reg_100238: 0x00??????
- * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */
+ /* XXX; reg_100238
+ * reg_100238: 0x00?????? */
timing->reg_10023c = 0x202;
- if(dev_priv->chipset < 0xa3) {
+ if (dev_priv->chipset < 0x98 ||
+ (dev_priv->chipset == 0x98 &&
+ dev_priv->stepping <= 0xa1)) {
timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
} else {
- /* currently unknown
+ /* XXX: reg_10023c
+ * currently unknown
* 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
}
+
+ /* XXX: reg_100240? */
}
+ timing->id = i;
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
timing->reg_100220, timing->reg_100224,
@@ -695,10 +712,11 @@ nouveau_mem_timing_init(struct drm_device *dev)
NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
timing->reg_100230, timing->reg_100234,
timing->reg_100238, timing->reg_10023c);
+ NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240);
}
memtimings->nr_timing = entries;
- memtimings->supported = true;
+ memtimings->supported = (dev_priv->chipset <= 0x98);
}
void
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index 67a16e01ffa6..8f97016f5b26 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -361,20 +361,6 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
return 0;
}
-
-static uint32_t
-nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- /*XXX: dodgy hack for now */
- if (dev_priv->card_type >= NV_50)
- return 24;
- if (dev_priv->card_type >= NV_40)
- return 32;
- return 16;
-}
-
/*
DMA objects are used to reference a piece of memory in the
framebuffer, PCI or AGP address space. Each object is 16 bytes big
@@ -606,11 +592,11 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
set to 0?
*/
static int
-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
- struct nouveau_gpuobj **gpuobj_ret)
+nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_gpuobj *gpuobj;
+ int ret;
gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
if (!gpuobj)
@@ -624,8 +610,10 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
spin_lock(&dev_priv->ramin_lock);
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
spin_unlock(&dev_priv->ramin_lock);
- *gpuobj_ret = gpuobj;
- return 0;
+
+ ret = nouveau_ramht_insert(chan, handle, gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return ret;
}
int
@@ -634,101 +622,30 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj_class *oc;
- struct nouveau_gpuobj *gpuobj;
int ret;
NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
list_for_each_entry(oc, &dev_priv->classes, head) {
- if (oc->id == class)
- goto found;
- }
-
- NV_ERROR(dev, "illegal object class: 0x%x\n", class);
- return -EINVAL;
+ struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
-found:
- switch (oc->engine) {
- case NVOBJ_ENGINE_SW:
- if (dev_priv->card_type < NV_C0) {
- ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj);
- if (ret)
- return ret;
- goto insert;
- }
- break;
- case NVOBJ_ENGINE_GR:
- if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) ||
- (dev_priv->card_type < NV_20 && !chan->pgraph_ctx)) {
- struct nouveau_pgraph_engine *pgraph =
- &dev_priv->engine.graph;
+ if (oc->id != class)
+ continue;
- ret = pgraph->create_context(chan);
- if (ret)
- return ret;
- }
- break;
- case NVOBJ_ENGINE_CRYPT:
- if (!chan->crypt_ctx) {
- struct nouveau_crypt_engine *pcrypt =
- &dev_priv->engine.crypt;
+ if (oc->engine == NVOBJ_ENGINE_SW)
+ return nouveau_gpuobj_sw_new(chan, handle, class);
- ret = pcrypt->create_context(chan);
+ if (!chan->engctx[oc->engine]) {
+ ret = eng->context_new(chan, oc->engine);
if (ret)
return ret;
}
- break;
- }
-
- /* we're done if this is fermi */
- if (dev_priv->card_type >= NV_C0)
- return 0;
-
- ret = nouveau_gpuobj_new(dev, chan,
- nouveau_gpuobj_class_instmem_size(dev, class),
- 16,
- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
- &gpuobj);
- if (ret) {
- NV_ERROR(dev, "error creating gpuobj: %d\n", ret);
- return ret;
- }
- if (dev_priv->card_type >= NV_50) {
- nv_wo32(gpuobj, 0, class);
- nv_wo32(gpuobj, 20, 0x00010000);
- } else {
- switch (class) {
- case NV_CLASS_NULL:
- nv_wo32(gpuobj, 0, 0x00001030);
- nv_wo32(gpuobj, 4, 0xFFFFFFFF);
- break;
- default:
- if (dev_priv->card_type >= NV_40) {
- nv_wo32(gpuobj, 0, class);
-#ifdef __BIG_ENDIAN
- nv_wo32(gpuobj, 8, 0x01000000);
-#endif
- } else {
-#ifdef __BIG_ENDIAN
- nv_wo32(gpuobj, 0, class | 0x00080000);
-#else
- nv_wo32(gpuobj, 0, class);
-#endif
- }
- }
+ return eng->object_new(chan, oc->engine, handle, class);
}
- dev_priv->engine.instmem.flush(dev);
-
- gpuobj->engine = oc->engine;
- gpuobj->class = oc->id;
-insert:
- ret = nouveau_ramht_insert(chan, handle, gpuobj);
- if (ret)
- NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret);
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return ret;
+ NV_ERROR(dev, "illegal object class: 0x%x\n", class);
+ return -EINVAL;
}
static int
@@ -746,9 +663,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
size = 0x2000;
base = 0;
- /* PGRAPH context */
- size += dev_priv->engine.graph.grctx_size;
-
if (dev_priv->card_type == NV_50) {
/* Various fixed table thingos */
size += 0x1400; /* mostly unknown stuff */
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 670e3cb697ec..922fb6b664ed 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -72,6 +72,68 @@ legacy_perf_init(struct drm_device *dev)
pm->nr_perflvl = 1;
}
+static struct nouveau_pm_memtiming *
+nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
+ u16 memclk, u8 *entry, u8 recordlen, u8 entries)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nvbios *bios = &dev_priv->vbios;
+ u8 ramcfg;
+ int i;
+
+ /* perf v2 has a separate "timing map" table, we have to match
+ * the target memory clock to a specific entry, *then* use
+ * ramcfg to select the correct subentry
+ */
+ if (P->version == 2) {
+ u8 *tmap = ROMPTR(bios, P->data[4]);
+ if (!tmap) {
+ NV_DEBUG(dev, "no timing map pointer\n");
+ return NULL;
+ }
+
+ if (tmap[0] != 0x10) {
+ NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
+ return NULL;
+ }
+
+ entry = tmap + tmap[1];
+ recordlen = tmap[2] + (tmap[4] * tmap[3]);
+ for (i = 0; i < tmap[5]; i++, entry += recordlen) {
+ if (memclk >= ROM16(entry[0]) &&
+ memclk <= ROM16(entry[2]))
+ break;
+ }
+
+ if (i == tmap[5]) {
+ NV_WARN(dev, "no match in timing map table\n");
+ return NULL;
+ }
+
+ entry += tmap[2];
+ recordlen = tmap[3];
+ entries = tmap[4];
+ }
+
+ ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
+ if (bios->ram_restrict_tbl_ptr)
+ ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
+
+ if (ramcfg >= entries) {
+ NV_WARN(dev, "ramcfg strap out of bounds!\n");
+ return NULL;
+ }
+
+ entry += ramcfg * recordlen;
+ if (entry[1] >= pm->memtimings.nr_timing) {
+ NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
+ return NULL;
+ }
+
+ return &pm->memtimings.timing[entry[1]];
+}
+
void
nouveau_perf_init(struct drm_device *dev)
{
@@ -124,6 +186,8 @@ nouveau_perf_init(struct drm_device *dev)
for (i = 0; i < entries; i++) {
struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
+ perflvl->timing = NULL;
+
if (entry[0] == 0xff) {
entry += recordlen;
continue;
@@ -174,9 +238,21 @@ nouveau_perf_init(struct drm_device *dev)
#define subent(n) entry[perf[2] + ((n) * perf[3])]
perflvl->fanspeed = 0; /*XXX*/
perflvl->voltage = entry[2];
- perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
- perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
- perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+ if (dev_priv->card_type == NV_50) {
+ perflvl->core = ROM16(subent(0)) & 0xfff;
+ perflvl->shader = ROM16(subent(1)) & 0xfff;
+ perflvl->memory = ROM16(subent(2)) & 0xfff;
+ } else {
+ perflvl->shader = ROM16(subent(3)) & 0xfff;
+ perflvl->core = perflvl->shader / 2;
+ perflvl->unk0a = ROM16(subent(4)) & 0xfff;
+ perflvl->memory = ROM16(subent(5)) & 0xfff;
+ }
+
+ perflvl->core *= 1000;
+ perflvl->shader *= 1000;
+ perflvl->memory *= 1000;
+ perflvl->unk0a *= 1000;
break;
}
@@ -190,6 +266,16 @@ nouveau_perf_init(struct drm_device *dev)
}
}
+ /* get the corresponding memory timings */
+ if (version > 0x15) {
+ /* last 3 args are for < 0x40, ignored for >= 0x40 */
+ perflvl->timing =
+ nouveau_perf_timing(dev, &P,
+ perflvl->memory / 1000,
+ entry + perf[3],
+ perf[5], perf[4]);
+ }
+
snprintf(perflvl->name, sizeof(perflvl->name),
"performance_level_%d", i);
perflvl->id = i;
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 4399e2f34db4..da8d994d5e8a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -156,7 +156,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
static void
nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
{
- char c[16], s[16], v[16], f[16];
+ char c[16], s[16], v[16], f[16], t[16];
c[0] = '\0';
if (perflvl->core)
@@ -174,8 +174,12 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
if (perflvl->fanspeed)
snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
- snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
- c, s, v, f);
+ t[0] = '\0';
+ if (perflvl->timing)
+ snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
+
+ snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000,
+ c, s, v, f, t);
}
static ssize_t
@@ -449,7 +453,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
#endif
}
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
static int
nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
{
@@ -476,10 +480,10 @@ nouveau_pm_init(struct drm_device *dev)
char info[256];
int ret, i;
+ nouveau_mem_timing_init(dev);
nouveau_volt_init(dev);
nouveau_perf_init(dev);
nouveau_temp_init(dev);
- nouveau_mem_timing_init(dev);
NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
for (i = 0; i < pm->nr_perflvl; i++) {
@@ -490,6 +494,7 @@ nouveau_pm_init(struct drm_device *dev)
/* determine current ("boot") performance level */
ret = nouveau_pm_perflvl_get(dev, &pm->boot);
if (ret == 0) {
+ strncpy(pm->boot.name, "boot", 4);
pm->cur = &pm->boot;
nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
@@ -507,7 +512,7 @@ nouveau_pm_init(struct drm_device *dev)
nouveau_sysfs_init(dev);
nouveau_hwmon_init(dev);
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
pm->acpi_nb.notifier_call = nouveau_pm_acpi_event;
register_acpi_notifier(&pm->acpi_nb);
#endif
@@ -524,12 +529,12 @@ nouveau_pm_fini(struct drm_device *dev)
if (pm->cur != &pm->boot)
nouveau_pm_perflvl_set(dev, &pm->boot);
- nouveau_mem_timing_fini(dev);
nouveau_temp_fini(dev);
nouveau_perf_fini(dev);
nouveau_volt_fini(dev);
+ nouveau_mem_timing_fini(dev);
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
unregister_acpi_notifier(&pm->acpi_nb);
#endif
nouveau_hwmon_fini(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 04e8fb795269..f18cdfc3400f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -639,9 +639,9 @@
# define NV50_PCONNECTOR_I2C_PORT_4 0x0000e240
# define NV50_PCONNECTOR_I2C_PORT_5 0x0000e258
-#define NV50_AUXCH_DATA_OUT(i,n) ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
+#define NV50_AUXCH_DATA_OUT(i, n) ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
#define NV50_AUXCH_DATA_OUT__SIZE 4
-#define NV50_AUXCH_DATA_IN(i,n) ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
+#define NV50_AUXCH_DATA_IN(i, n) ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
#define NV50_AUXCH_DATA_IN__SIZE 4
#define NV50_AUXCH_ADDR(i) ((i) * 0x50 + 0x0000e4e0)
#define NV50_AUXCH_CTRL(i) ((i) * 0x50 + 0x0000e4e4)
@@ -829,7 +829,7 @@
#define NV50_PDISPLAY_SOR_BACKLIGHT 0x0061c084
#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000
#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff
-#define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_CTRL(i, l) (0x0061c10c + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_CTRL_ENABLED 0x00000001
#define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000
#define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000
@@ -841,10 +841,10 @@
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_DISABLED 0x00000000
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_1 0x01000000
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000
-#define NV50_SOR_DP_UNK118(i,l) (0x0061c118 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK120(i,l) (0x0061c120 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK128(i,l) (0x0061c128 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK130(i,l) (0x0061c130 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK118(i, l) (0x0061c118 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK128(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80)
#define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000)
#define NV50_PDISPLAY_USER_PUT(i) ((i) * 0x1000 + 0x00640000)
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index a30adec5beaa..38ea662568c1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -65,14 +65,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv04_fb_init;
engine->fb.takedown = nv04_fb_takedown;
- engine->graph.init = nv04_graph_init;
- engine->graph.takedown = nv04_graph_takedown;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.channel = nv04_graph_channel;
- engine->graph.create_context = nv04_graph_create_context;
- engine->graph.destroy_context = nv04_graph_destroy_context;
- engine->graph.load_context = nv04_graph_load_context;
- engine->graph.unload_context = nv04_graph_unload_context;
engine->fifo.channels = 16;
engine->fifo.init = nv04_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -98,8 +90,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -123,15 +113,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv10_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv10_fb_free_tile_region;
- engine->graph.init = nv10_graph_init;
- engine->graph.takedown = nv10_graph_takedown;
- engine->graph.channel = nv10_graph_channel;
- engine->graph.create_context = nv10_graph_create_context;
- engine->graph.destroy_context = nv10_graph_destroy_context;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.load_context = nv10_graph_load_context;
- engine->graph.unload_context = nv10_graph_unload_context;
- engine->graph.set_tile_region = nv10_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -157,8 +138,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -182,15 +161,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv10_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv10_fb_free_tile_region;
- engine->graph.init = nv20_graph_init;
- engine->graph.takedown = nv20_graph_takedown;
- engine->graph.channel = nv10_graph_channel;
- engine->graph.create_context = nv20_graph_create_context;
- engine->graph.destroy_context = nv20_graph_destroy_context;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.load_context = nv20_graph_load_context;
- engine->graph.unload_context = nv20_graph_unload_context;
- engine->graph.set_tile_region = nv20_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -216,8 +186,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -241,15 +209,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv30_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv30_fb_free_tile_region;
- engine->graph.init = nv30_graph_init;
- engine->graph.takedown = nv20_graph_takedown;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.channel = nv10_graph_channel;
- engine->graph.create_context = nv20_graph_create_context;
- engine->graph.destroy_context = nv20_graph_destroy_context;
- engine->graph.load_context = nv20_graph_load_context;
- engine->graph.unload_context = nv20_graph_unload_context;
- engine->graph.set_tile_region = nv20_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -277,8 +236,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_set = nv04_pm_clock_set;
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -303,15 +260,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv30_fb_init_tile_region;
engine->fb.set_tile_region = nv40_fb_set_tile_region;
engine->fb.free_tile_region = nv30_fb_free_tile_region;
- engine->graph.init = nv40_graph_init;
- engine->graph.takedown = nv40_graph_takedown;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.channel = nv40_graph_channel;
- engine->graph.create_context = nv40_graph_create_context;
- engine->graph.destroy_context = nv40_graph_destroy_context;
- engine->graph.load_context = nv40_graph_load_context;
- engine->graph.unload_context = nv40_graph_unload_context;
- engine->graph.set_tile_region = nv40_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv40_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -340,8 +288,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
engine->pm.temp_get = nv40_temp_get;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -368,19 +314,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv50_fb_init;
engine->fb.takedown = nv50_fb_takedown;
- engine->graph.init = nv50_graph_init;
- engine->graph.takedown = nv50_graph_takedown;
- engine->graph.fifo_access = nv50_graph_fifo_access;
- engine->graph.channel = nv50_graph_channel;
- engine->graph.create_context = nv50_graph_create_context;
- engine->graph.destroy_context = nv50_graph_destroy_context;
- engine->graph.load_context = nv50_graph_load_context;
- engine->graph.unload_context = nv50_graph_unload_context;
- if (dev_priv->chipset == 0x50 ||
- dev_priv->chipset == 0xac)
- engine->graph.tlb_flush = nv50_graph_tlb_flush;
- else
- engine->graph.tlb_flush = nv84_graph_tlb_flush;
engine->fifo.channels = 128;
engine->fifo.init = nv50_fifo_init;
engine->fifo.takedown = nv50_fifo_takedown;
@@ -432,24 +365,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.temp_get = nv84_temp_get;
else
engine->pm.temp_get = nv40_temp_get;
- switch (dev_priv->chipset) {
- case 0x84:
- case 0x86:
- case 0x92:
- case 0x94:
- case 0x96:
- case 0xa0:
- engine->crypt.init = nv84_crypt_init;
- engine->crypt.takedown = nv84_crypt_fini;
- engine->crypt.create_context = nv84_crypt_create_context;
- engine->crypt.destroy_context = nv84_crypt_destroy_context;
- engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
- break;
- default:
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
- break;
- }
engine->vram.init = nv50_vram_init;
engine->vram.get = nv50_vram_new;
engine->vram.put = nv50_vram_del;
@@ -472,14 +387,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nvc0_fb_init;
engine->fb.takedown = nvc0_fb_takedown;
- engine->graph.init = nvc0_graph_init;
- engine->graph.takedown = nvc0_graph_takedown;
- engine->graph.fifo_access = nvc0_graph_fifo_access;
- engine->graph.channel = nvc0_graph_channel;
- engine->graph.create_context = nvc0_graph_create_context;
- engine->graph.destroy_context = nvc0_graph_destroy_context;
- engine->graph.load_context = nvc0_graph_load_context;
- engine->graph.unload_context = nvc0_graph_unload_context;
engine->fifo.channels = 128;
engine->fifo.init = nvc0_fifo_init;
engine->fifo.takedown = nvc0_fifo_takedown;
@@ -503,8 +410,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.irq_register = nv50_gpio_irq_register;
engine->gpio.irq_unregister = nv50_gpio_irq_unregister;
engine->gpio.irq_enable = nv50_gpio_irq_enable;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nvc0_vram_init;
engine->vram.get = nvc0_vram_new;
engine->vram.put = nv50_vram_del;
@@ -593,7 +498,7 @@ nouveau_card_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine;
- int ret;
+ int ret, e = 0;
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
@@ -658,23 +563,80 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_timer;
- if (nouveau_noaccel)
- engine->graph.accel_blocked = true;
- else {
- /* PGRAPH */
- ret = engine->graph.init(dev);
- if (ret)
- goto out_fb;
+ switch (dev_priv->card_type) {
+ case NV_04:
+ nv04_graph_create(dev);
+ break;
+ case NV_10:
+ nv10_graph_create(dev);
+ break;
+ case NV_20:
+ case NV_30:
+ nv20_graph_create(dev);
+ break;
+ case NV_40:
+ nv40_graph_create(dev);
+ break;
+ case NV_50:
+ nv50_graph_create(dev);
+ break;
+ case NV_C0:
+ nvc0_graph_create(dev);
+ break;
+ default:
+ break;
+ }
- /* PCRYPT */
- ret = engine->crypt.init(dev);
- if (ret)
- goto out_graph;
+ switch (dev_priv->chipset) {
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0xa0:
+ nv84_crypt_create(dev);
+ break;
+ }
+
+ switch (dev_priv->card_type) {
+ case NV_50:
+ switch (dev_priv->chipset) {
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ case 0xaf:
+ nva3_copy_create(dev);
+ break;
+ }
+ break;
+ case NV_C0:
+ nvc0_copy_create(dev, 0);
+ nvc0_copy_create(dev, 1);
+ break;
+ default:
+ break;
+ }
+
+ if (dev_priv->card_type == NV_40)
+ nv40_mpeg_create(dev);
+ else
+ if (dev_priv->card_type == NV_50 &&
+ (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0))
+ nv50_mpeg_create(dev);
+
+ if (!nouveau_noaccel) {
+ for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
+ if (dev_priv->eng[e]) {
+ ret = dev_priv->eng[e]->init(dev, e);
+ if (ret)
+ goto out_engine;
+ }
+ }
/* PFIFO */
ret = engine->fifo.init(dev);
if (ret)
- goto out_crypt;
+ goto out_engine;
}
ret = engine->display.create(dev);
@@ -691,7 +653,7 @@ nouveau_card_init(struct drm_device *dev)
/* what about PVIDEO/PCRTC/PRAMDAC etc? */
- if (!engine->graph.accel_blocked) {
+ if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
ret = nouveau_fence_init(dev);
if (ret)
goto out_irq;
@@ -715,13 +677,16 @@ out_vblank:
out_fifo:
if (!nouveau_noaccel)
engine->fifo.takedown(dev);
-out_crypt:
- if (!nouveau_noaccel)
- engine->crypt.takedown(dev);
-out_graph:
- if (!nouveau_noaccel)
- engine->graph.takedown(dev);
-out_fb:
+out_engine:
+ if (!nouveau_noaccel) {
+ for (e = e - 1; e >= 0; e--) {
+ if (!dev_priv->eng[e])
+ continue;
+ dev_priv->eng[e]->fini(dev, e);
+ dev_priv->eng[e]->destroy(dev,e );
+ }
+ }
+
engine->fb.takedown(dev);
out_timer:
engine->timer.takedown(dev);
@@ -751,16 +716,21 @@ static void nouveau_card_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
+ int e;
- if (!engine->graph.accel_blocked) {
+ if (dev_priv->channel) {
nouveau_fence_fini(dev);
nouveau_channel_put_unlocked(&dev_priv->channel);
}
if (!nouveau_noaccel) {
engine->fifo.takedown(dev);
- engine->crypt.takedown(dev);
- engine->graph.takedown(dev);
+ for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+ if (dev_priv->eng[e]) {
+ dev_priv->eng[e]->fini(dev, e);
+ dev_priv->eng[e]->destroy(dev,e );
+ }
+ }
}
engine->fb.takedown(dev);
engine->timer.takedown(dev);
@@ -768,6 +738,11 @@ static void nouveau_card_takedown(struct drm_device *dev)
engine->mc.takedown(dev);
engine->display.late_takedown(dev);
+ if (dev_priv->vga_ram) {
+ nouveau_bo_unpin(dev_priv->vga_ram);
+ nouveau_bo_ref(NULL, &dev_priv->vga_ram);
+ }
+
mutex_lock(&dev->struct_mutex);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
@@ -861,7 +836,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
#ifdef CONFIG_X86
primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
#endif
-
+
remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);
return 0;
}
@@ -913,11 +888,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
/* Time to determine the card architecture */
reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+ dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */
/* We're dealing with >=NV10 */
if ((reg0 & 0x0f000000) > 0) {
/* Bit 27-20 contain the architecture in hex */
dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+ dev_priv->stepping = (reg0 & 0xff);
/* NV04 or NV05 */
} else if ((reg0 & 0xff00fff0) == 0x20004000) {
if (reg0 & 0x00f00000)
diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h
index 2e06b55cfdc1..c48a9fc2b47b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_vm.h
@@ -53,8 +53,7 @@ struct nouveau_vm {
int refcount;
struct list_head pgd_list;
- atomic_t pgraph_refs;
- atomic_t pcrypt_refs;
+ atomic_t engref[16];
struct nouveau_vm_pgt *pgt;
u32 fpde;
diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c
index 04fdc00a67d5..75e872741d92 100644
--- a/drivers/gpu/drm/nouveau/nouveau_volt.c
+++ b/drivers/gpu/drm/nouveau/nouveau_volt.c
@@ -159,8 +159,16 @@ nouveau_volt_init(struct drm_device *dev)
headerlen = volt[1];
recordlen = volt[2];
entries = volt[3];
- vidshift = hweight8(volt[5]);
vidmask = volt[4];
+ /* no longer certain what volt[5] is, if it's related to
+ * the vid shift then it's definitely not a function of
+ * how many bits are set.
+ *
+ * after looking at a number of nva3+ vbios images, they
+ * all seem likely to have a static shift of 2.. lets
+ * go with that for now until proven otherwise.
+ */
+ vidshift = 2;
break;
default:
NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 748b9d9c2949..3c78bc81357e 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -790,8 +790,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
if (atomic) {
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
- }
- else {
+ } else {
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
@@ -944,14 +943,14 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
struct drm_gem_object *gem;
int ret = 0;
- if (width != 64 || height != 64)
- return -EINVAL;
-
if (!buffer_handle) {
nv_crtc->cursor.hide(nv_crtc, true);
return 0;
}
+ if (width != 64 || height != 64)
+ return -EINVAL;
+
gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
if (!gem)
return -ENOENT;
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index af75015068d6..3626ee7db3ba 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -28,9 +28,11 @@
#include "nouveau_drv.h"
#include "nouveau_hw.h"
#include "nouveau_util.h"
+#include "nouveau_ramht.h"
-static int nv04_graph_register(struct drm_device *dev);
-static void nv04_graph_isr(struct drm_device *dev);
+struct nv04_graph_engine {
+ struct nouveau_exec_engine base;
+};
static uint32_t nv04_graph_ctx_regs[] = {
0x0040053c,
@@ -350,7 +352,7 @@ struct graph_state {
uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
};
-struct nouveau_channel *
+static struct nouveau_channel *
nv04_graph_channel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -365,26 +367,6 @@ nv04_graph_channel(struct drm_device *dev)
return dev_priv->channels.ptr[chid];
}
-static void
-nv04_graph_context_switch(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_channel *chan = NULL;
- int chid;
-
- nouveau_wait_for_idle(dev);
-
- /* If previous context is valid, we need to save it */
- pgraph->unload_context(dev);
-
- /* Load context for next channel */
- chid = dev_priv->engine.fifo.channel_id(dev);
- chan = dev_priv->channels.ptr[chid];
- if (chan)
- nv04_graph_load_context(chan);
-}
-
static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
{
int i;
@@ -397,48 +379,11 @@ static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
return NULL;
}
-int nv04_graph_create_context(struct nouveau_channel *chan)
-{
- struct graph_state *pgraph_ctx;
- NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
-
- chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
- GFP_KERNEL);
- if (pgraph_ctx == NULL)
- return -ENOMEM;
-
- *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
- return 0;
-}
-
-void nv04_graph_destroy_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
- unsigned long flags;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
-
- /* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
-
- /* Free the context resources */
- kfree(pgraph_ctx);
- chan->pgraph_ctx = NULL;
-
- pgraph->fifo_access(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-}
-
-int nv04_graph_load_context(struct nouveau_channel *chan)
+static int
+nv04_graph_load_context(struct nouveau_channel *chan)
{
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
uint32_t tmp;
int i;
@@ -456,20 +401,19 @@ int nv04_graph_load_context(struct nouveau_channel *chan)
return 0;
}
-int
+static int
nv04_graph_unload_context(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_channel *chan = NULL;
struct graph_state *ctx;
uint32_t tmp;
int i;
- chan = pgraph->channel(dev);
+ chan = nv04_graph_channel(dev);
if (!chan)
return 0;
- ctx = chan->pgraph_ctx;
+ ctx = chan->engctx[NVOBJ_ENGINE_GR];
for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]);
@@ -481,23 +425,85 @@ nv04_graph_unload_context(struct drm_device *dev)
return 0;
}
-int nv04_graph_init(struct drm_device *dev)
+static int
+nv04_graph_context_new(struct nouveau_channel *chan, int engine)
{
+ struct graph_state *pgraph_ctx;
+ NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
+
+ pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
+ if (pgraph_ctx == NULL)
+ return -ENOMEM;
+
+ *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+ chan->engctx[engine] = pgraph_ctx;
+ return 0;
+}
+
+static void
+nv04_graph_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t tmp;
+ struct graph_state *pgraph_ctx = chan->engctx[engine];
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv04_graph_fifo_access(dev, false);
+
+ /* Unload the context if it's the currently active one */
+ if (nv04_graph_channel(dev) == chan)
+ nv04_graph_unload_context(dev);
+
+ nv04_graph_fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the context resources */
+ kfree(pgraph_ctx);
+ chan->engctx[engine] = NULL;
+}
+
+int
+nv04_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
int ret;
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 1;
+ obj->class = class;
+
+#ifdef __BIG_ENDIAN
+ nv_wo32(obj, 0x00, 0x00080000 | class);
+#else
+ nv_wo32(obj, 0x00, class);
+#endif
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static int
+nv04_graph_init(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
- ret = nv04_graph_register(dev);
- if (ret)
- return ret;
-
/* Enable PGRAPH interrupts */
- nouveau_irq_register(dev, 12, nv04_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -507,7 +513,7 @@ int nv04_graph_init(struct drm_device *dev)
nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000);
/*1231C000 blob, 001 haiku*/
- //*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+ /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100);
/*0x72111100 blob , 01 haiku*/
/*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
@@ -531,10 +537,12 @@ int nv04_graph_init(struct drm_device *dev)
return 0;
}
-void nv04_graph_takedown(struct drm_device *dev)
+static int
+nv04_graph_fini(struct drm_device *dev, int engine)
{
+ nv04_graph_unload_context(dev);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
- nouveau_irq_unregister(dev, 12);
+ return 0;
}
void
@@ -969,13 +977,138 @@ nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
return 1;
}
-static int
-nv04_graph_register(struct drm_device *dev)
+static struct nouveau_bitfield nv04_graph_intr[] = {
+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+ {}
+};
+
+static struct nouveau_bitfield nv04_graph_nstatus[] = {
+ { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
+ { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
+ { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
+ { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
+ {}
+};
+
+struct nouveau_bitfield nv04_graph_nsource[] = {
+ { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
+ { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
+ { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
+ { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
+ { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
+ { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
+ { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
+ { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
+ { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
+ {}
+};
+
+static void
+nv04_graph_context_switch(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = NULL;
+ int chid;
- if (dev_priv->engine.graph.registered)
- return 0;
+ nouveau_wait_for_idle(dev);
+
+ /* If previous context is valid, we need to save it */
+ nv04_graph_unload_context(dev);
+
+ /* Load context for next channel */
+ chid = dev_priv->engine.fifo.channel_id(dev);
+ chan = dev_priv->channels.ptr[chid];
+ if (chan)
+ nv04_graph_load_context(chan);
+}
+
+static void
+nv04_graph_isr(struct drm_device *dev)
+{
+ u32 stat;
+
+ while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+ u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x0f000000) >> 24;
+ u32 subc = (addr & 0x0000e000) >> 13;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
+ u32 show = stat;
+
+ if (stat & NV_PGRAPH_INTR_NOTIFY) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+ show &= ~NV_PGRAPH_INTR_NOTIFY;
+ }
+ }
+
+ if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+ nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ nv04_graph_context_switch(dev);
+ }
+
+ nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+ nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PGRAPH -");
+ nouveau_bitfield_print(nv04_graph_intr, show);
+ printk(" nsource:");
+ nouveau_bitfield_print(nv04_graph_nsource, nsource);
+ printk(" nstatus:");
+ nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ chid, subc, class, mthd, data);
+ }
+ }
+}
+
+static void
+nv04_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv04_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(pgraph);
+}
+
+int
+nv04_graph_create(struct drm_device *dev)
+{
+ struct nv04_graph_engine *pgraph;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv04_graph_destroy;
+ pgraph->base.init = nv04_graph_init;
+ pgraph->base.fini = nv04_graph_fini;
+ pgraph->base.context_new = nv04_graph_context_new;
+ pgraph->base.context_del = nv04_graph_context_del;
+ pgraph->base.object_new = nv04_graph_object_new;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv04_graph_isr);
/* dvd subpicture */
NVOBJ_CLASS(dev, 0x0038, GR);
@@ -1222,93 +1355,5 @@ nv04_graph_register(struct drm_device *dev)
NVOBJ_CLASS(dev, 0x506e, SW);
NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
return 0;
-};
-
-static struct nouveau_bitfield nv04_graph_intr[] = {
- { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
- {}
-};
-
-static struct nouveau_bitfield nv04_graph_nstatus[] =
-{
- { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
- { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
- { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
- { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
- {}
-};
-
-struct nouveau_bitfield nv04_graph_nsource[] =
-{
- { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
- { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
- { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
- { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
- { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
- { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
- { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
- { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
- { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
- { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
- {}
-};
-
-static void
-nv04_graph_isr(struct drm_device *dev)
-{
- u32 stat;
-
- while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
- u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
- u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
- u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
- u32 chid = (addr & 0x0f000000) >> 24;
- u32 subc = (addr & 0x0000e000) >> 13;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
- u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
- u32 show = stat;
-
- if (stat & NV_PGRAPH_INTR_NOTIFY) {
- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
- if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
- show &= ~NV_PGRAPH_INTR_NOTIFY;
- }
- }
-
- if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
- stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- nv04_graph_context_switch(dev);
- }
-
- nv_wr32(dev, NV03_PGRAPH_INTR, stat);
- nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
- if (show && nouveau_ratelimit()) {
- NV_INFO(dev, "PGRAPH -");
- nouveau_bitfield_print(nv04_graph_intr, show);
- printk(" nsource:");
- nouveau_bitfield_print(nv04_graph_nsource, nsource);
- printk(" nstatus:");
- nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
- printk("\n");
- NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
- "mthd 0x%04x data 0x%08x\n",
- chid, subc, class, mthd, data);
- }
- }
}
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index b8e3edb5c063..b8611b955313 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -95,6 +95,9 @@ nv04_instmem_takedown(struct drm_device *dev)
nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
+
+ if (drm_mm_initialized(&dev_priv->ramin_heap))
+ drm_mm_takedown(&dev_priv->ramin_heap);
}
int
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index 8c92edb7bbcd..0930c6cb88e0 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -28,10 +28,9 @@
#include "nouveau_drv.h"
#include "nouveau_util.h"
-static int nv10_graph_register(struct drm_device *);
-static void nv10_graph_isr(struct drm_device *);
-
-#define NV10_FIFO_NUMBER 32
+struct nv10_graph_engine {
+ struct nouveau_exec_engine base;
+};
struct pipe_state {
uint32_t pipe_0x0000[0x040/4];
@@ -414,9 +413,9 @@ struct graph_state {
static void nv10_graph_save_pipe(struct nouveau_channel *chan)
{
- struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+ struct drm_device *dev = chan->dev;
PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
@@ -432,9 +431,9 @@ static void nv10_graph_save_pipe(struct nouveau_channel *chan)
static void nv10_graph_load_pipe(struct nouveau_channel *chan)
{
- struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+ struct drm_device *dev = chan->dev;
uint32_t xfmode0, xfmode1;
int i;
@@ -482,9 +481,9 @@ static void nv10_graph_load_pipe(struct nouveau_channel *chan)
static void nv10_graph_create_pipe(struct nouveau_channel *chan)
{
- struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
+ struct drm_device *dev = chan->dev;
uint32_t *fifo_pipe_state_addr;
int i;
#define PIPE_INIT(addr) \
@@ -661,8 +660,6 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
uint32_t inst)
{
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
uint32_t ctx_user, ctx_switch[5];
int i, subchan = -1;
@@ -711,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
- pgraph->fifo_access(dev, true);
- pgraph->fifo_access(dev, false);
+ nv04_graph_fifo_access(dev, true);
+ nv04_graph_fifo_access(dev, false);
/* Restore the FIFO state */
for (i = 0; i < ARRAY_SIZE(fifo); i++)
@@ -729,11 +726,12 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
}
-int nv10_graph_load_context(struct nouveau_channel *chan)
+static int
+nv10_graph_load_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
uint32_t tmp;
int i;
@@ -757,21 +755,20 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
return 0;
}
-int
+static int
nv10_graph_unload_context(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan;
struct graph_state *ctx;
uint32_t tmp;
int i;
- chan = pgraph->channel(dev);
+ chan = nv10_graph_channel(dev);
if (!chan)
return 0;
- ctx = chan->pgraph_ctx;
+ ctx = chan->engctx[NVOBJ_ENGINE_GR];
for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
@@ -805,7 +802,7 @@ nv10_graph_context_switch(struct drm_device *dev)
/* Load context for next channel */
chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
chan = dev_priv->channels.ptr[chid];
- if (chan && chan->pgraph_ctx)
+ if (chan && chan->engctx[NVOBJ_ENGINE_GR])
nv10_graph_load_context(chan);
}
@@ -836,7 +833,8 @@ nv10_graph_channel(struct drm_device *dev)
return dev_priv->channels.ptr[chid];
}
-int nv10_graph_create_context(struct nouveau_channel *chan)
+static int
+nv10_graph_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -844,11 +842,10 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
- chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
- GFP_KERNEL);
+ pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
if (pgraph_ctx == NULL)
return -ENOMEM;
-
+ chan->engctx[engine] = pgraph_ctx;
NV_WRITE_CTX(0x00400e88, 0x08000000);
NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -873,30 +870,30 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
return 0;
}
-void nv10_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv10_graph_context_del(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[engine];
unsigned long flags;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
+ nv04_graph_fifo_access(dev, false);
/* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
+ if (nv10_graph_channel(dev) == chan)
+ nv10_graph_unload_context(dev);
+
+ nv04_graph_fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Free the context resources */
+ chan->engctx[engine] = NULL;
kfree(pgraph_ctx);
- chan->pgraph_ctx = NULL;
-
- pgraph->fifo_access(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
}
-void
+static void
nv10_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -907,22 +904,18 @@ nv10_graph_set_tile_region(struct drm_device *dev, int i)
nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
}
-int nv10_graph_init(struct drm_device *dev)
+static int
+nv10_graph_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t tmp;
- int ret, i;
+ u32 tmp;
+ int i;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
- ret = nv10_graph_register(dev);
- if (ret)
- return ret;
-
- nouveau_irq_register(dev, 12, nv10_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -963,18 +956,20 @@ int nv10_graph_init(struct drm_device *dev)
return 0;
}
-void nv10_graph_takedown(struct drm_device *dev)
+static int
+nv10_graph_fini(struct drm_device *dev, int engine)
{
+ nv10_graph_unload_context(dev);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
- nouveau_irq_unregister(dev, 12);
+ return 0;
}
static int
nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data)
{
+ struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
- struct graph_state *ctx = chan->pgraph_ctx;
struct pipe_state *pipe = &ctx->pipe_state;
uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
uint32_t xfmode0, xfmode1;
@@ -1061,64 +1056,13 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
return 0;
}
-static int
-nv10_graph_register(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
- NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
- NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
- NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
- /* celcius */
- if (dev_priv->chipset <= 0x10) {
- NVOBJ_CLASS(dev, 0x0056, GR);
- } else
- if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
- NVOBJ_CLASS(dev, 0x0096, GR);
- } else {
- NVOBJ_CLASS(dev, 0x0099, GR);
- NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
- }
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
- return 0;
-}
-
struct nouveau_bitfield nv10_graph_intr[] = {
{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
{ NV_PGRAPH_INTR_ERROR, "ERROR" },
{}
};
-struct nouveau_bitfield nv10_graph_nstatus[] =
-{
+struct nouveau_bitfield nv10_graph_nstatus[] = {
{ NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
{ NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
{ NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
@@ -1173,3 +1117,73 @@ nv10_graph_isr(struct drm_device *dev)
}
}
}
+
+static void
+nv10_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+ kfree(pgraph);
+}
+
+int
+nv10_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv10_graph_engine *pgraph;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv10_graph_destroy;
+ pgraph->base.init = nv10_graph_init;
+ pgraph->base.fini = nv10_graph_fini;
+ pgraph->base.context_new = nv10_graph_context_new;
+ pgraph->base.context_del = nv10_graph_context_del;
+ pgraph->base.object_new = nv04_graph_object_new;
+ pgraph->base.set_tile_region = nv10_graph_set_tile_region;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv10_graph_isr);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
+ NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
+ NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
+ NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
+
+ /* celcius */
+ if (dev_priv->chipset <= 0x10) {
+ NVOBJ_CLASS(dev, 0x0056, GR);
+ } else
+ if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
+ NVOBJ_CLASS(dev, 0x0096, GR);
+ } else {
+ NVOBJ_CLASS(dev, 0x0099, GR);
+ NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 8464b76798d5..affc7d7dd029 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -24,6 +24,14 @@
*
*/
+struct nv20_graph_engine {
+ struct nouveau_exec_engine base;
+ struct nouveau_gpuobj *ctxtab;
+ void (*grctx_init)(struct nouveau_gpuobj *);
+ u32 grctx_size;
+ u32 grctx_user;
+};
+
#define NV20_GRCTX_SIZE (3580*4)
#define NV25_GRCTX_SIZE (3529*4)
#define NV2A_GRCTX_SIZE (3500*4)
@@ -32,12 +40,54 @@
#define NV34_GRCTX_SIZE (18140)
#define NV35_36_GRCTX_SIZE (22396)
-static int nv20_graph_register(struct drm_device *);
-static int nv30_graph_register(struct drm_device *);
-static void nv20_graph_isr(struct drm_device *);
+int
+nv20_graph_unload_context(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_channel *chan;
+ struct nouveau_gpuobj *grctx;
+ u32 tmp;
+
+ chan = nv10_graph_channel(dev);
+ if (!chan)
+ return 0;
+ grctx = chan->engctx[NVOBJ_ENGINE_GR];
+
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->pinst >> 4);
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+ NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
+
+ nouveau_wait_for_idle(dev);
+
+ nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+ tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
+ tmp |= (pfifo->channels - 1) << 24;
+ nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+ return 0;
+}
+
+static void
+nv20_graph_rdi(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int i, writecount = 32;
+ uint32_t rdi_index = 0x2c80000;
+
+ if (dev_priv->chipset == 0x20) {
+ rdi_index = 0x3d0000;
+ writecount = 15;
+ }
+
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
+ for (i = 0; i < writecount; i++)
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
+
+ nouveau_wait_for_idle(dev);
+}
static void
-nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv20_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -87,7 +137,7 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv25_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -146,7 +196,7 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv2a_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -196,7 +246,7 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv30_31_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -254,7 +304,7 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv34_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -312,7 +362,7 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv35_36_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -370,148 +420,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
int
-nv20_graph_create_context(struct nouveau_channel *chan)
+nv20_graph_context_new(struct nouveau_channel *chan, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+ struct nouveau_gpuobj *grctx = NULL;
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
- unsigned int idoffs = 0x28;
int ret;
- switch (dev_priv->chipset) {
- case 0x20:
- ctx_init = nv20_graph_context_init;
- idoffs = 0;
- break;
- case 0x25:
- case 0x28:
- ctx_init = nv25_graph_context_init;
- break;
- case 0x2a:
- ctx_init = nv2a_graph_context_init;
- idoffs = 0;
- break;
- case 0x30:
- case 0x31:
- ctx_init = nv30_31_graph_context_init;
- break;
- case 0x34:
- ctx_init = nv34_graph_context_init;
- break;
- case 0x35:
- case 0x36:
- ctx_init = nv35_36_graph_context_init;
- break;
- default:
- BUG_ON(1);
- }
-
- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &grctx);
if (ret)
return ret;
/* Initialise default context values */
- ctx_init(dev, chan->ramin_grctx);
+ pgraph->grctx_init(grctx);
/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
- nv_wo32(chan->ramin_grctx, idoffs,
- (chan->id << 24) | 0x1); /* CTX_USER */
+ /* CTX_USER */
+ nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1);
- nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
+ nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->pinst >> 4);
+ chan->engctx[engine] = grctx;
return 0;
}
void
-nv20_graph_destroy_context(struct nouveau_channel *chan)
+nv20_graph_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+ struct nouveau_gpuobj *grctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
unsigned long flags;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
+ nv04_graph_fifo_access(dev, false);
/* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
+ if (nv10_graph_channel(dev) == chan)
+ nv20_graph_unload_context(dev);
- pgraph->fifo_access(dev, true);
+ nv04_graph_fifo_access(dev, true);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Free the context resources */
- nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
-int
-nv20_graph_load_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
- uint32_t inst;
+ nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
- if (!chan->ramin_grctx)
- return -EINVAL;
- inst = chan->ramin_grctx->pinst >> 4;
-
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
- NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD);
- nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-
- nouveau_wait_for_idle(dev);
- return 0;
-}
-
-int
-nv20_graph_unload_context(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_channel *chan;
- uint32_t inst, tmp;
-
- chan = pgraph->channel(dev);
- if (!chan)
- return 0;
- inst = chan->ramin_grctx->pinst >> 4;
-
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
- NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
-
- nouveau_wait_for_idle(dev);
-
- nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
- tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
- tmp |= (pfifo->channels - 1) << 24;
- nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
- return 0;
+ nouveau_gpuobj_ref(NULL, &grctx);
+ chan->engctx[engine] = NULL;
}
static void
-nv20_graph_rdi(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i, writecount = 32;
- uint32_t rdi_index = 0x2c80000;
-
- if (dev_priv->chipset == 0x20) {
- rdi_index = 0x3d0000;
- writecount = 15;
- }
-
- nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
- for (i = 0; i < writecount; i++)
- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
-
- nouveau_wait_for_idle(dev);
-}
-
-void
nv20_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -536,56 +495,22 @@ nv20_graph_set_tile_region(struct drm_device *dev, int i)
}
int
-nv20_graph_init(struct drm_device *dev)
+nv20_graph_init(struct drm_device *dev, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t tmp, vramsz;
- int ret, i;
-
- switch (dev_priv->chipset) {
- case 0x20:
- pgraph->grctx_size = NV20_GRCTX_SIZE;
- break;
- case 0x25:
- case 0x28:
- pgraph->grctx_size = NV25_GRCTX_SIZE;
- break;
- case 0x2a:
- pgraph->grctx_size = NV2A_GRCTX_SIZE;
- break;
- default:
- NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
- pgraph->accel_blocked = true;
- return 0;
- }
+ int i;
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
- if (!pgraph->ctx_table) {
- /* Create Context Pointer Table */
- ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pgraph->ctx_table);
- if (ret)
- return ret;
- }
-
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- pgraph->ctx_table->pinst >> 4);
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
nv20_graph_rdi(dev);
- ret = nv20_graph_register(dev);
- if (ret) {
- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
- return ret;
- }
-
- nouveau_irq_register(dev, 12, nv20_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -657,67 +582,20 @@ nv20_graph_init(struct drm_device *dev)
return 0;
}
-void
-nv20_graph_takedown(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
- nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
- nouveau_irq_unregister(dev, 12);
-
- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-}
-
int
-nv30_graph_init(struct drm_device *dev)
+nv30_graph_init(struct drm_device *dev, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- int ret, i;
-
- switch (dev_priv->chipset) {
- case 0x30:
- case 0x31:
- pgraph->grctx_size = NV30_31_GRCTX_SIZE;
- break;
- case 0x34:
- pgraph->grctx_size = NV34_GRCTX_SIZE;
- break;
- case 0x35:
- case 0x36:
- pgraph->grctx_size = NV35_36_GRCTX_SIZE;
- break;
- default:
- NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
- pgraph->accel_blocked = true;
- return 0;
- }
+ int i;
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
- if (!pgraph->ctx_table) {
- /* Create Context Pointer Table */
- ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pgraph->ctx_table);
- if (ret)
- return ret;
- }
-
- ret = nv30_graph_register(dev);
- if (ret) {
- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
- return ret;
- }
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- pgraph->ctx_table->pinst >> 4);
-
- nouveau_irq_register(dev, 12, nv20_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -775,85 +653,11 @@ nv30_graph_init(struct drm_device *dev)
return 0;
}
-static int
-nv20_graph_register(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
- NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
-
- /* kelvin */
- if (dev_priv->chipset < 0x25)
- NVOBJ_CLASS(dev, 0x0097, GR);
- else
- NVOBJ_CLASS(dev, 0x0597, GR);
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
- return 0;
-}
-
-static int
-nv30_graph_register(struct drm_device *dev)
+int
+nv20_graph_fini(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
-
- /* rankine */
- if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
- NVOBJ_CLASS(dev, 0x0397, GR);
- else
- if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
- NVOBJ_CLASS(dev, 0x0697, GR);
- else
- if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
- NVOBJ_CLASS(dev, 0x0497, GR);
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
+ nv20_graph_unload_context(dev);
+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
return 0;
}
@@ -897,3 +701,135 @@ nv20_graph_isr(struct drm_device *dev)
}
}
}
+
+static void
+nv20_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+ nouveau_gpuobj_ref(NULL, &pgraph->ctxtab);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(pgraph);
+}
+
+int
+nv20_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv20_graph_engine *pgraph;
+ int ret;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv20_graph_destroy;
+ pgraph->base.fini = nv20_graph_fini;
+ pgraph->base.context_new = nv20_graph_context_new;
+ pgraph->base.context_del = nv20_graph_context_del;
+ pgraph->base.object_new = nv04_graph_object_new;
+ pgraph->base.set_tile_region = nv20_graph_set_tile_region;
+
+ pgraph->grctx_user = 0x0028;
+ if (dev_priv->card_type == NV_20) {
+ pgraph->base.init = nv20_graph_init;
+ switch (dev_priv->chipset) {
+ case 0x20:
+ pgraph->grctx_init = nv20_graph_context_init;
+ pgraph->grctx_size = NV20_GRCTX_SIZE;
+ pgraph->grctx_user = 0x0000;
+ break;
+ case 0x25:
+ case 0x28:
+ pgraph->grctx_init = nv25_graph_context_init;
+ pgraph->grctx_size = NV25_GRCTX_SIZE;
+ break;
+ case 0x2a:
+ pgraph->grctx_init = nv2a_graph_context_init;
+ pgraph->grctx_size = NV2A_GRCTX_SIZE;
+ pgraph->grctx_user = 0x0000;
+ break;
+ default:
+ NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+ return 0;
+ }
+ } else {
+ pgraph->base.init = nv30_graph_init;
+ switch (dev_priv->chipset) {
+ case 0x30:
+ case 0x31:
+ pgraph->grctx_init = nv30_31_graph_context_init;
+ pgraph->grctx_size = NV30_31_GRCTX_SIZE;
+ break;
+ case 0x34:
+ pgraph->grctx_init = nv34_graph_context_init;
+ pgraph->grctx_size = NV34_GRCTX_SIZE;
+ break;
+ case 0x35:
+ case 0x36:
+ pgraph->grctx_init = nv35_36_graph_context_init;
+ pgraph->grctx_size = NV35_36_GRCTX_SIZE;
+ break;
+ default:
+ NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+ return 0;
+ }
+ }
+
+ /* Create Context Pointer Table */
+ ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC,
+ &pgraph->ctxtab);
+ if (ret) {
+ kfree(pgraph);
+ return ret;
+ }
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv20_graph_isr);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ if (dev_priv->card_type == NV_20) {
+ NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
+ NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
+
+ /* kelvin */
+ if (dev_priv->chipset < 0x25)
+ NVOBJ_CLASS(dev, 0x0097, GR);
+ else
+ NVOBJ_CLASS(dev, 0x0597, GR);
+ } else {
+ NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
+ NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
+ NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
+ NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
+
+ /* rankine */
+ if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0397, GR);
+ else
+ if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0697, GR);
+ else
+ if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0497, GR);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index 49b9a35a9cd6..68cb2d991c88 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -115,6 +115,7 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68));
nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
+ nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84));
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
@@ -186,6 +187,7 @@ nv40_fifo_unload_context(struct drm_device *dev)
tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
nv_wi32(dev, fc + 72, tmp);
#endif
+ nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c));
nv40_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index fceb44c0ec74..5beb01b8ace1 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -28,14 +28,18 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_grctx.h"
+#include "nouveau_ramht.h"
-static int nv40_graph_register(struct drm_device *);
-static void nv40_graph_isr(struct drm_device *);
+struct nv40_graph_engine {
+ struct nouveau_exec_engine base;
+ u32 grctx_size;
+};
-struct nouveau_channel *
+static struct nouveau_channel *
nv40_graph_channel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *grctx;
uint32_t inst;
int i;
@@ -45,74 +49,17 @@ nv40_graph_channel(struct drm_device *dev)
inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (!dev_priv->channels.ptr[i])
+ continue;
- if (chan && chan->ramin_grctx &&
- chan->ramin_grctx->pinst == inst)
- return chan;
+ grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
+ if (grctx && grctx->pinst == inst)
+ return dev_priv->channels.ptr[i];
}
return NULL;
}
-int
-nv40_graph_create_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_grctx ctx = {};
- unsigned long flags;
- int ret;
-
- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
- if (ret)
- return ret;
-
- /* Initialise default context values */
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx;
- nv40_grctx_init(&ctx);
-
- nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
-
- /* init grctx pointer in ramfc, and on PFIFO if channel is
- * already active there
- */
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4);
- nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
- if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
- nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4);
- nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- return 0;
-}
-
-void
-nv40_graph_destroy_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- unsigned long flags;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
-
- /* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
-
- pgraph->fifo_access(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
- /* Free the context resources */
- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
static int
nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
{
@@ -154,57 +101,115 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
return 0;
}
-/* Restore the context for a specific channel into PGRAPH */
-int
-nv40_graph_load_context(struct nouveau_channel *chan)
+static int
+nv40_graph_unload_context(struct drm_device *dev)
{
- struct drm_device *dev = chan->dev;
uint32_t inst;
int ret;
- if (!chan->ramin_grctx)
- return -EINVAL;
- inst = chan->ramin_grctx->pinst >> 4;
+ inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
+ if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
+ return 0;
+ inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+ ret = nv40_graph_transfer_context(dev, inst, 1);
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+ return ret;
+}
+
+static int
+nv40_graph_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *grctx = NULL;
+ struct nouveau_grctx ctx = {};
+ unsigned long flags;
+ int ret;
- ret = nv40_graph_transfer_context(dev, inst, 0);
+ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &grctx);
if (ret)
return ret;
- /* 0x40032C, no idea of it's exact function. Could simply be a
- * record of the currently active PGRAPH context. It's currently
- * unknown as to what bit 24 does. The nv ddx has it set, so we will
- * set it here too.
- */
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR,
- (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) |
- NV40_PGRAPH_CTXCTL_CUR_LOADED);
- /* 0x32E0 records the instance address of the active FIFO's PGRAPH
- * context. If at any time this doesn't match 0x40032C, you will
- * receive PGRAPH_INTR_CONTEXT_SWITCH
+ /* Initialise default context values */
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = grctx;
+ nv40_grctx_init(&ctx);
+
+ nv_wo32(grctx, 0, grctx->vinst);
+
+ /* init grctx pointer in ramfc, and on PFIFO if channel is
+ * already active there
*/
- nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst);
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_wo32(chan->ramfc, 0x38, grctx->vinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+ if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
+ nv_wr32(dev, 0x0032e0, grctx->vinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ chan->engctx[engine] = grctx;
return 0;
}
-int
-nv40_graph_unload_context(struct drm_device *dev)
+static void
+nv40_graph_context_del(struct nouveau_channel *chan, int engine)
{
- uint32_t inst;
- int ret;
+ struct nouveau_gpuobj *grctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ unsigned long flags;
- inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
- return 0;
- inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv04_graph_fifo_access(dev, false);
- ret = nv40_graph_transfer_context(dev, inst, 1);
+ /* Unload the context if it's the currently active one */
+ if (nv40_graph_channel(dev) == chan)
+ nv40_graph_unload_context(dev);
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+ nv04_graph_fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the context resources */
+ nouveau_gpuobj_ref(NULL, &grctx);
+ chan->engctx[engine] = NULL;
+}
+
+int
+nv40_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 1;
+ obj->class = class;
+
+ nv_wo32(obj, 0x00, class);
+ nv_wo32(obj, 0x04, 0x00000000);
+#ifndef __BIG_ENDIAN
+ nv_wo32(obj, 0x08, 0x00000000);
+#else
+ nv_wo32(obj, 0x08, 0x01000000);
+#endif
+ nv_wo32(obj, 0x0c, 0x00000000);
+ nv_wo32(obj, 0x10, 0x00000000);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
return ret;
}
-void
+static void
nv40_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -257,14 +262,14 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
* C51 0x4e
*/
int
-nv40_graph_init(struct drm_device *dev)
+nv40_graph_init(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv =
- (struct drm_nouveau_private *)dev->dev_private;
+ struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nouveau_grctx ctx = {};
uint32_t vramsz, *cp;
- int ret, i, j;
+ int i, j;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
@@ -280,7 +285,7 @@ nv40_graph_init(struct drm_device *dev)
ctx.data = cp;
ctx.ctxprog_max = 256;
nv40_grctx_init(&ctx);
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+ pgraph->grctx_size = ctx.ctxvals_pos * 4;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
@@ -288,14 +293,9 @@ nv40_graph_init(struct drm_device *dev)
kfree(cp);
- ret = nv40_graph_register(dev);
- if (ret)
- return ret;
-
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
- nouveau_irq_register(dev, 12, nv40_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -428,47 +428,10 @@ nv40_graph_init(struct drm_device *dev)
return 0;
}
-void nv40_graph_takedown(struct drm_device *dev)
-{
- nouveau_irq_unregister(dev, 12);
-}
-
static int
-nv40_graph_register(struct drm_device *dev)
+nv40_graph_fini(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
-
- /* curie */
- if (nv44_graph_class(dev))
- NVOBJ_CLASS(dev, 0x4497, GR);
- else
- NVOBJ_CLASS(dev, 0x4097, GR);
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
+ nv40_graph_unload_context(dev);
return 0;
}
@@ -476,17 +439,17 @@ static int
nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan;
+ struct nouveau_gpuobj *grctx;
unsigned long flags;
int i;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- chan = dev_priv->channels.ptr[i];
- if (!chan || !chan->ramin_grctx)
+ if (!dev_priv->channels.ptr[i])
continue;
+ grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
- if (inst == chan->ramin_grctx->pinst)
+ if (grctx && grctx->pinst == inst)
break;
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
@@ -537,3 +500,63 @@ nv40_graph_isr(struct drm_device *dev)
}
}
}
+
+static void
+nv40_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(pgraph);
+}
+
+int
+nv40_graph_create(struct drm_device *dev)
+{
+ struct nv40_graph_engine *pgraph;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv40_graph_destroy;
+ pgraph->base.init = nv40_graph_init;
+ pgraph->base.fini = nv40_graph_fini;
+ pgraph->base.context_new = nv40_graph_context_new;
+ pgraph->base.context_del = nv40_graph_context_del;
+ pgraph->base.object_new = nv40_graph_object_new;
+ pgraph->base.set_tile_region = nv40_graph_set_tile_region;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv40_graph_isr);
+
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
+
+ /* curie */
+ if (nv44_graph_class(dev))
+ NVOBJ_CLASS(dev, 0x4497, GR);
+ else
+ NVOBJ_CLASS(dev, 0x4097, GR);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
new file mode 100644
index 000000000000..6d2af292a2e3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv40_mpeg.c
@@ -0,0 +1,311 @@
+/*
+ * 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
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv40_mpeg_engine {
+ struct nouveau_exec_engine base;
+};
+
+static int
+nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ctx = NULL;
+ unsigned long flags;
+ int ret;
+
+ NV_DEBUG(dev, "ch%d\n", chan->id);
+
+ ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ctx, 0x78, 0x02001ec1);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+ if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
+ nv_wr32(dev, 0x00330c, ctx->pinst >> 4);
+ nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static void
+nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ unsigned long flags;
+ u32 inst = 0x80000000 | (ctx->pinst >> 4);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ if (nv_rd32(dev, 0x00b318) == inst)
+ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ nouveau_gpuobj_ref(NULL, &ctx);
+ chan->engctx[engine] = NULL;
+}
+
+static int
+nv40_mpeg_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 2;
+ obj->class = class;
+
+ nv_wo32(obj, 0x00, class);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static int
+nv40_mpeg_init(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+ int i;
+
+ /* VPE init */
+ nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
+ nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+ nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+ for (i = 0; i < dev_priv->engine.fb.num_tiles; i++)
+ pmpeg->base.set_tile_region(dev, i);
+
+ /* PMPEG init */
+ nv_wr32(dev, 0x00b32c, 0x00000000);
+ nv_wr32(dev, 0x00b314, 0x00000100);
+ nv_wr32(dev, 0x00b220, 0x00000044);
+ nv_wr32(dev, 0x00b300, 0x02001ec1);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+ nv_wr32(dev, 0x00b100, 0xffffffff);
+ nv_wr32(dev, 0x00b140, 0xffffffff);
+
+ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nv40_mpeg_fini(struct drm_device *dev, int engine)
+{
+ /*XXX: context save? */
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x00b140, 0x00000000);
+ return 0;
+}
+
+static int
+nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ struct drm_device *dev = chan->dev;
+ u32 inst = data << 4;
+ u32 dma0 = nv_ri32(dev, inst + 0);
+ u32 dma1 = nv_ri32(dev, inst + 4);
+ u32 dma2 = nv_ri32(dev, inst + 8);
+ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+ u32 size = dma1 + 1;
+
+ /* only allow linear DMA objects */
+ if (!(dma0 & 0x00002000))
+ return -EINVAL;
+
+ if (mthd == 0x0190) {
+ /* DMA_CMD */
+ nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+ nv_wr32(dev, 0x00b334, base);
+ nv_wr32(dev, 0x00b324, size);
+ } else
+ if (mthd == 0x01a0) {
+ /* DMA_DATA */
+ nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+ nv_wr32(dev, 0x00b360, base);
+ nv_wr32(dev, 0x00b364, size);
+ } else {
+ /* DMA_IMAGE, VRAM only */
+ if (dma0 & 0x000c0000)
+ return -EINVAL;
+
+ nv_wr32(dev, 0x00b370, base);
+ nv_wr32(dev, 0x00b374, size);
+ }
+
+ return 0;
+}
+
+static int
+nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ctx;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ if (!dev_priv->channels.ptr[i])
+ continue;
+
+ ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
+ if (ctx && ctx->pinst == inst)
+ break;
+ }
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return i;
+}
+
+static void
+nv40_vpe_set_tile_region(struct drm_device *dev, int i)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+ nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
+ nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
+ nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+static void
+nv40_mpeg_isr(struct drm_device *dev)
+{
+ u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
+ u32 chid = nv40_mpeg_isr_chid(dev, inst);
+ u32 stat = nv_rd32(dev, 0x00b100);
+ u32 type = nv_rd32(dev, 0x00b230);
+ u32 mthd = nv_rd32(dev, 0x00b234);
+ u32 data = nv_rd32(dev, 0x00b238);
+ u32 show = stat;
+
+ if (stat & 0x01000000) {
+ /* happens on initial binding of the object */
+ if (type == 0x00000020 && mthd == 0x0000) {
+ nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
+ show &= ~0x01000000;
+ }
+
+ if (type == 0x00000010) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
+ show &= ~0x01000000;
+ }
+ }
+
+ nv_wr32(dev, 0x00b100, stat);
+ nv_wr32(dev, 0x00b230, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ chid, inst, stat, type, mthd, data);
+ }
+}
+
+static void
+nv40_vpe_isr(struct drm_device *dev)
+{
+ if (nv_rd32(dev, 0x00b100))
+ nv40_mpeg_isr(dev);
+
+ if (nv_rd32(dev, 0x00b800)) {
+ u32 stat = nv_rd32(dev, 0x00b800);
+ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+ nv_wr32(dev, 0xb800, stat);
+ }
+}
+
+static void
+nv40_mpeg_destroy(struct drm_device *dev, int engine)
+{
+ struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 0);
+
+ NVOBJ_ENGINE_DEL(dev, MPEG);
+ kfree(pmpeg);
+}
+
+int
+nv40_mpeg_create(struct drm_device *dev)
+{
+ struct nv40_mpeg_engine *pmpeg;
+
+ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+ if (!pmpeg)
+ return -ENOMEM;
+
+ pmpeg->base.destroy = nv40_mpeg_destroy;
+ pmpeg->base.init = nv40_mpeg_init;
+ pmpeg->base.fini = nv40_mpeg_fini;
+ pmpeg->base.context_new = nv40_mpeg_context_new;
+ pmpeg->base.context_del = nv40_mpeg_context_del;
+ pmpeg->base.object_new = nv40_mpeg_object_new;
+
+ /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between
+ * all VPE engines, for this driver's purposes the PMPEG engine
+ * will be treated as the "master" and handle the global VPE
+ * bits too
+ */
+ pmpeg->base.set_tile_region = nv40_vpe_set_tile_region;
+ nouveau_irq_register(dev, 0, nv40_vpe_isr);
+
+ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+ NVOBJ_CLASS(dev, 0x3174, MPEG);
+ NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma);
+ NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma);
+ NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma);
+
+#if 0
+ NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+ NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+ return 0;
+
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_calc.c b/drivers/gpu/drm/nouveau/nv50_calc.c
index de81151648f8..8cf63a8b30cd 100644
--- a/drivers/gpu/drm/nouveau/nv50_calc.c
+++ b/drivers/gpu/drm/nouveau/nv50_calc.c
@@ -23,7 +23,6 @@
*/
#include "drmP.h"
-#include "drm_fixed.h"
#include "nouveau_drv.h"
#include "nouveau_hw.h"
@@ -47,45 +46,52 @@ nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
}
int
-nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
- int *N, int *fN, int *M, int *P)
+nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
+ int *pN, int *pfN, int *pM, int *P)
{
- fixed20_12 fb_div, a, b;
- u32 refclk = pll->refclk / 10;
- u32 max_vco_freq = pll->vco1.maxfreq / 10;
- u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
- clk /= 10;
+ u32 best_err = ~0, err;
+ int M, lM, hM, N, fN;
- *P = max_vco_freq / clk;
+ *P = pll->vco1.maxfreq / clk;
if (*P > pll->max_p)
*P = pll->max_p;
if (*P < pll->min_p)
*P = pll->min_p;
- /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
- a.full = dfixed_const(refclk + max_vco_inputfreq);
- b.full = dfixed_const(max_vco_inputfreq);
- a.full = dfixed_div(a, b);
- a.full = dfixed_floor(a);
- *M = dfixed_trunc(a);
+ lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq;
+ lM = max(lM, (int)pll->vco1.min_m);
+ hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq;
+ hM = min(hM, (int)pll->vco1.max_m);
- /* fb_div = (vco * *M) / refclk; */
- fb_div.full = dfixed_const(clk * *P);
- fb_div.full = dfixed_mul(fb_div, a);
- a.full = dfixed_const(refclk);
- fb_div.full = dfixed_div(fb_div, a);
+ for (M = lM; M <= hM; M++) {
+ u32 tmp = clk * *P * M;
+ N = tmp / pll->refclk;
+ fN = tmp % pll->refclk;
+ if (!pfN && fN >= pll->refclk / 2)
+ N++;
- /* *N = floor(fb_div); */
- a.full = dfixed_floor(fb_div);
- *N = dfixed_trunc(fb_div);
+ if (N < pll->vco1.min_n)
+ continue;
+ if (N > pll->vco1.max_n)
+ break;
- /* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
- b.full = dfixed_const(8192);
- a.full = dfixed_mul(a, b);
- fb_div.full = dfixed_mul(fb_div, b);
- fb_div.full = fb_div.full - a.full;
- *fN = dfixed_trunc(fb_div) - 4096;
- *fN &= 0xffff;
+ err = abs(clk - (pll->refclk * N / M / *P));
+ if (err < best_err) {
+ best_err = err;
+ *pN = N;
+ *pM = M;
+ }
- return clk;
+ if (pfN) {
+ *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff;
+ return clk;
+ }
+ }
+
+ if (unlikely(best_err == ~0)) {
+ NV_ERROR(dev, "unable to find matching pll values\n");
+ return -EINVAL;
+ }
+
+ return pll->refclk * *pN / *pM / *P;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index a19ccaa025b3..ebabacf38da9 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -286,7 +286,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
} else
if (dev_priv->chipset < NV_C0) {
- ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+ ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0)
return 0;
@@ -298,7 +298,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
nv_wr32(dev, pll.reg + 8, N2);
} else {
- ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+ ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0)
return 0;
@@ -349,14 +349,14 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
struct drm_gem_object *gem;
int ret = 0, i;
- if (width != 64 || height != 64)
- return -EINVAL;
-
if (!buffer_handle) {
nv_crtc->cursor.hide(nv_crtc, true);
return 0;
}
+ if (width != 64 || height != 64)
+ return -EINVAL;
+
gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
if (!gem)
return -ENOENT;
@@ -532,8 +532,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
if (atomic) {
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
- }
- else {
+ } else {
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 75a376cc342a..74a3f6872701 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -517,13 +517,25 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
if (bios->fp.if_is_24bit)
script |= 0x0200;
} else {
+ /* determine number of lvds links */
+ if (nv_connector && nv_connector->edid &&
+ nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
+ /* http://www.spwg.org */
+ if (((u8 *)nv_connector->edid)[121] == 2)
+ script |= 0x0100;
+ } else
if (pxclk >= bios->fp.duallink_transition_clk) {
script |= 0x0100;
+ }
+
+ /* determine panel depth */
+ if (script & 0x0100) {
if (bios->fp.strapless_is_24bit & 2)
script |= 0x0200;
- } else
- if (bios->fp.strapless_is_24bit & 1)
- script |= 0x0200;
+ } else {
+ if (bios->fp.strapless_is_24bit & 1)
+ script |= 0x0200;
+ }
if (nv_connector && nv_connector->edid &&
(nv_connector->edid->revision >= 4) &&
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index b02a5b1e7d37..e25cbb46789a 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -31,10 +31,95 @@
#include "nouveau_grctx.h"
#include "nouveau_dma.h"
#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
#include "nv50_evo.h"
-static int nv50_graph_register(struct drm_device *);
-static void nv50_graph_isr(struct drm_device *);
+struct nv50_graph_engine {
+ struct nouveau_exec_engine base;
+ u32 ctxprog[512];
+ u32 ctxprog_size;
+ u32 grctx_size;
+};
+
+static void
+nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+ const uint32_t mask = 0x00010001;
+
+ if (enabled)
+ nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
+ else
+ nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
+}
+
+static struct nouveau_channel *
+nv50_graph_channel(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t inst;
+ int i;
+
+ /* Be sure we're not in the middle of a context switch or bad things
+ * will happen, such as unloading the wrong pgraph context.
+ */
+ if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
+ NV_ERROR(dev, "Ctxprog is still running\n");
+
+ inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+ if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+ return NULL;
+ inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
+
+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+
+ if (chan && chan->ramin && chan->ramin->vinst == inst)
+ return chan;
+ }
+
+ return NULL;
+}
+
+static int
+nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
+{
+ uint32_t fifo = nv_rd32(dev, 0x400500);
+
+ nv_wr32(dev, 0x400500, fifo & ~1);
+ nv_wr32(dev, 0x400784, inst);
+ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
+ nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
+ nv_wr32(dev, 0x400040, 0xffffffff);
+ (void)nv_rd32(dev, 0x400040);
+ nv_wr32(dev, 0x400040, 0x00000000);
+ nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
+
+ if (nouveau_wait_for_idle(dev))
+ nv_wr32(dev, 0x40032c, inst | (1<<31));
+ nv_wr32(dev, 0x400500, fifo);
+
+ return 0;
+}
+
+static int
+nv50_graph_unload_context(struct drm_device *dev)
+{
+ uint32_t inst;
+
+ inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+ if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+ return 0;
+ inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+ nouveau_wait_for_idle(dev);
+ nv_wr32(dev, 0x400784, inst);
+ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
+ nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
+ nouveau_wait_for_idle(dev);
+
+ nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
+ return 0;
+}
static void
nv50_graph_init_reset(struct drm_device *dev)
@@ -52,7 +137,6 @@ nv50_graph_init_intr(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
- nouveau_irq_register(dev, 12, nv50_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff);
nv_wr32(dev, 0x400138, 0xffffffff);
nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff);
@@ -135,34 +219,14 @@ nv50_graph_init_zcull(struct drm_device *dev)
static int
nv50_graph_init_ctxctl(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_grctx ctx = {};
- uint32_t *cp;
+ struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR);
int i;
NV_DEBUG(dev, "\n");
- cp = kmalloc(512 * 4, GFP_KERNEL);
- if (!cp) {
- NV_ERROR(dev, "failed to allocate ctxprog\n");
- dev_priv->engine.graph.accel_blocked = true;
- return 0;
- }
-
- ctx.dev = dev;
- ctx.mode = NOUVEAU_GRCTX_PROG;
- ctx.data = cp;
- ctx.ctxprog_max = 512;
- if (!nv50_grctx_init(&ctx)) {
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
- } else {
- dev_priv->engine.graph.accel_blocked = true;
- }
- kfree(cp);
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < pgraph->ctxprog_size; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]);
nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
nv_wr32(dev, 0x400320, 4);
@@ -171,8 +235,8 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
return 0;
}
-int
-nv50_graph_init(struct drm_device *dev)
+static int
+nv50_graph_init(struct drm_device *dev, int engine)
{
int ret;
@@ -186,105 +250,66 @@ nv50_graph_init(struct drm_device *dev)
if (ret)
return ret;
- ret = nv50_graph_register(dev);
- if (ret)
- return ret;
nv50_graph_init_intr(dev);
return 0;
}
-void
-nv50_graph_takedown(struct drm_device *dev)
+static int
+nv50_graph_fini(struct drm_device *dev, int engine)
{
NV_DEBUG(dev, "\n");
+ nv50_graph_unload_context(dev);
nv_wr32(dev, 0x40013c, 0x00000000);
- nouveau_irq_unregister(dev, 12);
-}
-
-void
-nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
-{
- const uint32_t mask = 0x00010001;
-
- if (enabled)
- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
- else
- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
-}
-
-struct nouveau_channel *
-nv50_graph_channel(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t inst;
- int i;
-
- /* Be sure we're not in the middle of a context switch or bad things
- * will happen, such as unloading the wrong pgraph context.
- */
- if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
- NV_ERROR(dev, "Ctxprog is still running\n");
-
- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
- return NULL;
- inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
-
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-
- if (chan && chan->ramin && chan->ramin->vinst == inst)
- return chan;
- }
-
- return NULL;
+ return 0;
}
-int
-nv50_graph_create_context(struct nouveau_channel *chan)
+static int
+nv50_graph_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_gpuobj *grctx = NULL;
+ struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
struct nouveau_grctx ctx = {};
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0,
+ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+ NVOBJ_FLAG_ZERO_FREE, &grctx);
if (ret)
return ret;
hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
nv_wo32(ramin, hdr + 0x00, 0x00190002);
- nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
- pgraph->grctx_size - 1);
- nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+ nv_wo32(ramin, hdr + 0x04, grctx->vinst + grctx->size - 1);
+ nv_wo32(ramin, hdr + 0x08, grctx->vinst);
nv_wo32(ramin, hdr + 0x0c, 0);
nv_wo32(ramin, hdr + 0x10, 0);
nv_wo32(ramin, hdr + 0x14, 0x00010000);
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx;
+ ctx.data = grctx;
nv50_grctx_init(&ctx);
- nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
+ nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12);
dev_priv->engine.instmem.flush(dev);
- atomic_inc(&chan->vm->pgraph_refs);
+
+ atomic_inc(&chan->vm->engref[NVOBJ_ENGINE_GR]);
+ chan->engctx[NVOBJ_ENGINE_GR] = grctx;
return 0;
}
-void
-nv50_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv50_graph_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nouveau_gpuobj *grctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
unsigned long flags;
@@ -296,72 +321,49 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
pfifo->reassign(dev, false);
- pgraph->fifo_access(dev, false);
+ nv50_graph_fifo_access(dev, false);
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
+ if (nv50_graph_channel(dev) == chan)
+ nv50_graph_unload_context(dev);
for (i = hdr; i < hdr + 24; i += 4)
nv_wo32(chan->ramin, i, 0);
dev_priv->engine.instmem.flush(dev);
- pgraph->fifo_access(dev, true);
+ nv50_graph_fifo_access(dev, true);
pfifo->reassign(dev, true);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+ nouveau_gpuobj_ref(NULL, &grctx);
- atomic_dec(&chan->vm->pgraph_refs);
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = NULL;
}
static int
-nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
-{
- uint32_t fifo = nv_rd32(dev, 0x400500);
-
- nv_wr32(dev, 0x400500, fifo & ~1);
- nv_wr32(dev, 0x400784, inst);
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
- nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
- nv_wr32(dev, 0x400040, 0xffffffff);
- (void)nv_rd32(dev, 0x400040);
- nv_wr32(dev, 0x400040, 0x00000000);
- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
-
- if (nouveau_wait_for_idle(dev))
- nv_wr32(dev, 0x40032c, inst | (1<<31));
- nv_wr32(dev, 0x400500, fifo);
-
- return 0;
-}
-
-int
-nv50_graph_load_context(struct nouveau_channel *chan)
-{
- uint32_t inst = chan->ramin->vinst >> 12;
-
- NV_DEBUG(chan->dev, "ch%d\n", chan->id);
- return nv50_graph_do_load_context(chan->dev, inst);
-}
-
-int
-nv50_graph_unload_context(struct drm_device *dev)
+nv50_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
{
- uint32_t inst;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
- return 0;
- inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 1;
+ obj->class = class;
- nouveau_wait_for_idle(dev);
- nv_wr32(dev, 0x400784, inst);
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
- nouveau_wait_for_idle(dev);
+ nv_wo32(obj, 0x00, class);
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
- return 0;
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
}
static void
@@ -442,68 +444,15 @@ nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
return 0;
}
-static int
-nv50_graph_register(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
- NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
- NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
- NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
-
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
-
- /* tesla */
- if (dev_priv->chipset == 0x50)
- NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
- else
- if (dev_priv->chipset < 0xa0)
- NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
- else {
- switch (dev_priv->chipset) {
- case 0xa0:
- case 0xaa:
- case 0xac:
- NVOBJ_CLASS(dev, 0x8397, GR);
- break;
- case 0xa3:
- case 0xa5:
- case 0xa8:
- NVOBJ_CLASS(dev, 0x8597, GR);
- break;
- case 0xaf:
- NVOBJ_CLASS(dev, 0x8697, GR);
- break;
- }
- }
-
- /* compute */
- NVOBJ_CLASS(dev, 0x50c0, GR);
- if (dev_priv->chipset > 0xa0 &&
- dev_priv->chipset != 0xaa &&
- dev_priv->chipset != 0xac)
- NVOBJ_CLASS(dev, 0x85c0, GR);
-
- dev_priv->engine.graph.registered = true;
- return 0;
-}
-void
-nv50_graph_tlb_flush(struct drm_device *dev)
+static void
+nv50_graph_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0);
}
-void
-nv84_graph_tlb_flush(struct drm_device *dev)
+static void
+nv84_graph_tlb_flush(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
@@ -548,8 +497,7 @@ nv84_graph_tlb_flush(struct drm_device *dev)
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
}
-static struct nouveau_enum nv50_mp_exec_error_names[] =
-{
+static struct nouveau_enum nv50_mp_exec_error_names[] = {
{ 3, "STACK_UNDERFLOW", NULL },
{ 4, "QUADON_ACTIVE", NULL },
{ 8, "TIMEOUT", NULL },
@@ -663,7 +611,7 @@ nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
nv_rd32(dev, addr + 0x20);
pc = nv_rd32(dev, addr + 0x24);
oplow = nv_rd32(dev, addr + 0x70);
- ophigh= nv_rd32(dev, addr + 0x74);
+ ophigh = nv_rd32(dev, addr + 0x74);
NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
"TP %d MP %d: ", tpid, i);
nouveau_enum_print(nv50_mp_exec_error_names, status);
@@ -991,7 +939,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid
return 1;
}
-static int
+int
nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1073,3 +1021,101 @@ nv50_graph_isr(struct drm_device *dev)
if (nv_rd32(dev, 0x400824) & (1 << 31))
nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
}
+
+static void
+nv50_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+
+ nouveau_irq_unregister(dev, 12);
+ kfree(pgraph);
+}
+
+int
+nv50_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_graph_engine *pgraph;
+ struct nouveau_grctx ctx = {};
+ int ret;
+
+ pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = pgraph->ctxprog;
+ ctx.ctxprog_max = ARRAY_SIZE(pgraph->ctxprog);
+
+ ret = nv50_grctx_init(&ctx);
+ if (ret) {
+ NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
+ kfree(pgraph);
+ return 0;
+ }
+
+ pgraph->grctx_size = ctx.ctxvals_pos * 4;
+ pgraph->ctxprog_size = ctx.ctxprog_len;
+
+ pgraph->base.destroy = nv50_graph_destroy;
+ pgraph->base.init = nv50_graph_init;
+ pgraph->base.fini = nv50_graph_fini;
+ pgraph->base.context_new = nv50_graph_context_new;
+ pgraph->base.context_del = nv50_graph_context_del;
+ pgraph->base.object_new = nv50_graph_object_new;
+ if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
+ pgraph->base.tlb_flush = nv50_graph_tlb_flush;
+ else
+ pgraph->base.tlb_flush = nv84_graph_tlb_flush;
+
+ nouveau_irq_register(dev, 12, nv50_graph_isr);
+
+ /* NVSW really doesn't live here... */
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
+ NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
+ NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
+ NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+
+ /* tesla */
+ if (dev_priv->chipset == 0x50)
+ NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
+ else
+ if (dev_priv->chipset < 0xa0)
+ NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
+ else {
+ switch (dev_priv->chipset) {
+ case 0xa0:
+ case 0xaa:
+ case 0xac:
+ NVOBJ_CLASS(dev, 0x8397, GR);
+ break;
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ NVOBJ_CLASS(dev, 0x8597, GR);
+ break;
+ case 0xaf:
+ NVOBJ_CLASS(dev, 0x8697, GR);
+ break;
+ }
+ }
+
+ /* compute */
+ NVOBJ_CLASS(dev, 0x50c0, GR);
+ if (dev_priv->chipset > 0xa0 &&
+ dev_priv->chipset != 0xaa &&
+ dev_priv->chipset != 0xac)
+ NVOBJ_CLASS(dev, 0x85c0, GR);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
index 336aab2a24a6..de9abff12b90 100644
--- a/drivers/gpu/drm/nouveau/nv50_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
@@ -747,7 +747,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
gr_def(ctx, offset + 0x64, 0x0000001f);
gr_def(ctx, offset + 0x68, 0x0000000f);
gr_def(ctx, offset + 0x6c, 0x0000000f);
- } else if(dev_priv->chipset < 0xa0) {
+ } else if (dev_priv->chipset < 0xa0) {
cp_ctx(ctx, offset + 0x50, 1);
cp_ctx(ctx, offset + 0x70, 1);
} else {
@@ -924,7 +924,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
} else {
dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
- }
+ }
dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */
if (dev_priv->chipset != 0x50)
dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */
@@ -1803,9 +1803,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
xf_emit(ctx, 1, 0); /* 1ff */
xf_emit(ctx, 8, 0); /* 0? */
xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
- }
- else
- {
+ } else {
xf_emit(ctx, 0xc, 0); /* RO */
/* SEEK */
xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
@@ -2836,7 +2834,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
if (IS_NVA3F(dev_priv->chipset))
xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- if(dev_priv->chipset == 0x50)
+ if (dev_priv->chipset == 0x50)
xf_emit(ctx, 1, 0); /* ff */
else
xf_emit(ctx, 3, 0); /* 1, 7, 3ff */
diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
new file mode 100644
index 000000000000..1dc5913f78c5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_mpeg.c
@@ -0,0 +1,256 @@
+/*
+ * 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
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv50_mpeg_engine {
+ struct nouveau_exec_engine base;
+};
+
+static inline u32
+CTX_PTR(struct drm_device *dev, u32 offset)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->chipset == 0x50)
+ offset += 0x0260;
+ else
+ offset += 0x0060;
+
+ return offset;
+}
+
+static int
+nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx = NULL;
+ int ret;
+
+ NV_DEBUG(dev, "ch%d\n", chan->id);
+
+ ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002);
+ nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->vinst + ctx->size - 1);
+ nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->vinst);
+ nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0);
+ nv_wo32(ramin, CTX_PTR(dev, 0x10), 0);
+ nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000);
+
+ nv_wo32(ctx, 0x70, 0x00801ec1);
+ nv_wo32(ctx, 0x7c, 0x0000037c);
+ dev_priv->engine.instmem.flush(dev);
+
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static void
+nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ unsigned long flags;
+ u32 inst, i;
+
+ if (!chan->ramin)
+ return;
+
+ inst = chan->ramin->vinst >> 12;
+ inst |= 0x80000000;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ if (nv_rd32(dev, 0x00b318) == inst)
+ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ for (i = 0x00; i <= 0x14; i += 4)
+ nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
+ nouveau_gpuobj_ref(NULL, &ctx);
+ chan->engctx[engine] = NULL;
+}
+
+static int
+nv50_mpeg_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 2;
+ obj->class = class;
+
+ nv_wo32(obj, 0x00, class);
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ dev_priv->engine.instmem.flush(dev);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static void
+nv50_mpeg_tlb_flush(struct drm_device *dev, int engine)
+{
+ nv50_vm_flush_engine(dev, 0x08);
+}
+
+static int
+nv50_mpeg_init(struct drm_device *dev, int engine)
+{
+ nv_wr32(dev, 0x00b32c, 0x00000000);
+ nv_wr32(dev, 0x00b314, 0x00000100);
+ nv_wr32(dev, 0x00b0e0, 0x0000001a);
+
+ nv_wr32(dev, 0x00b220, 0x00000044);
+ nv_wr32(dev, 0x00b300, 0x00801ec1);
+ nv_wr32(dev, 0x00b390, 0x00000000);
+ nv_wr32(dev, 0x00b394, 0x00000000);
+ nv_wr32(dev, 0x00b398, 0x00000000);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+ nv_wr32(dev, 0x00b100, 0xffffffff);
+ nv_wr32(dev, 0x00b140, 0xffffffff);
+
+ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nv50_mpeg_fini(struct drm_device *dev, int engine)
+{
+ /*XXX: context save for s/r */
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x00b140, 0x00000000);
+ return 0;
+}
+
+static void
+nv50_mpeg_isr(struct drm_device *dev)
+{
+ u32 stat = nv_rd32(dev, 0x00b100);
+ u32 type = nv_rd32(dev, 0x00b230);
+ u32 mthd = nv_rd32(dev, 0x00b234);
+ u32 data = nv_rd32(dev, 0x00b238);
+ u32 show = stat;
+
+ if (stat & 0x01000000) {
+ /* happens on initial binding of the object */
+ if (type == 0x00000020 && mthd == 0x0000) {
+ nv_wr32(dev, 0x00b308, 0x00000100);
+ show &= ~0x01000000;
+ }
+ }
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ stat, type, mthd, data);
+ }
+
+ nv_wr32(dev, 0x00b100, stat);
+ nv_wr32(dev, 0x00b230, 0x00000001);
+ nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nv50_vpe_isr(struct drm_device *dev)
+{
+ if (nv_rd32(dev, 0x00b100))
+ nv50_mpeg_isr(dev);
+
+ if (nv_rd32(dev, 0x00b800)) {
+ u32 stat = nv_rd32(dev, 0x00b800);
+ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+ nv_wr32(dev, 0xb800, stat);
+ }
+}
+
+static void
+nv50_mpeg_destroy(struct drm_device *dev, int engine)
+{
+ struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 0);
+
+ NVOBJ_ENGINE_DEL(dev, MPEG);
+ kfree(pmpeg);
+}
+
+int
+nv50_mpeg_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_mpeg_engine *pmpeg;
+
+ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+ if (!pmpeg)
+ return -ENOMEM;
+
+ pmpeg->base.destroy = nv50_mpeg_destroy;
+ pmpeg->base.init = nv50_mpeg_init;
+ pmpeg->base.fini = nv50_mpeg_fini;
+ pmpeg->base.context_new = nv50_mpeg_context_new;
+ pmpeg->base.context_del = nv50_mpeg_context_del;
+ pmpeg->base.object_new = nv50_mpeg_object_new;
+ pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush;
+
+ if (dev_priv->chipset == 0x50) {
+ nouveau_irq_register(dev, 0, nv50_vpe_isr);
+ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+ NVOBJ_CLASS(dev, 0x3174, MPEG);
+#if 0
+ NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+ NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+ } else {
+ nouveau_irq_register(dev, 0, nv50_mpeg_isr);
+ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+ NVOBJ_CLASS(dev, 0x8274, MPEG);
+ }
+
+ return 0;
+
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index 7dbb305d7e63..8a2810011bda 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -47,6 +47,21 @@ nv50_pm_clock_get(struct drm_device *dev, u32 id)
reg0 = nv_rd32(dev, pll.reg + 0);
reg1 = nv_rd32(dev, pll.reg + 4);
+
+ if ((reg0 & 0x80000000) == 0) {
+ if (id == PLL_SHADER) {
+ NV_DEBUG(dev, "Shader PLL is disabled. "
+ "Shader clock is twice the core\n");
+ ret = nv50_pm_clock_get(dev, PLL_CORE);
+ if (ret > 0)
+ return ret << 1;
+ } else if (id == PLL_MEMORY) {
+ NV_DEBUG(dev, "Memory PLL is disabled. "
+ "Memory clock is equal to the ref_clk\n");
+ return pll.refclk;
+ }
+ }
+
P = (reg0 & 0x00070000) >> 16;
N = (reg1 & 0x0000ff00) >> 8;
M = (reg1 & 0x000000ff);
diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c
index 6c2694490741..1a0dd491a0e4 100644
--- a/drivers/gpu/drm/nouveau/nv50_vm.c
+++ b/drivers/gpu/drm/nouveau/nv50_vm.c
@@ -151,8 +151,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+ int i;
pinstmem->flush(vm->dev);
@@ -163,11 +162,10 @@ nv50_vm_flush(struct nouveau_vm *vm)
}
pfifo->tlb_flush(vm->dev);
-
- if (atomic_read(&vm->pgraph_refs))
- pgraph->tlb_flush(vm->dev);
- if (atomic_read(&vm->pcrypt_refs))
- pcrypt->tlb_flush(vm->dev);
+ for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+ if (atomic_read(&vm->engref[i]))
+ dev_priv->eng[i]->tlb_flush(vm->dev, i);
+ }
}
void
diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c
index fabc7fd30b1d..75b809a51748 100644
--- a/drivers/gpu/drm/nouveau/nv84_crypt.c
+++ b/drivers/gpu/drm/nouveau/nv84_crypt.c
@@ -26,46 +26,48 @@
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
-static void nv84_crypt_isr(struct drm_device *);
+struct nv84_crypt_engine {
+ struct nouveau_exec_engine base;
+};
-int
-nv84_crypt_create_context(struct nouveau_channel *chan)
+static int
+nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx;
int ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
- ret = nouveau_gpuobj_new(dev, chan, 256, 0,
- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
- &chan->crypt_ctx);
+ ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
if (ret)
return ret;
nv_wo32(ramin, 0xa0, 0x00190000);
- nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
- nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
+ nv_wo32(ramin, 0xa4, ctx->vinst + ctx->size - 1);
+ nv_wo32(ramin, 0xa8, ctx->vinst);
nv_wo32(ramin, 0xac, 0);
nv_wo32(ramin, 0xb0, 0);
nv_wo32(ramin, 0xb4, 0);
-
dev_priv->engine.instmem.flush(dev);
- atomic_inc(&chan->vm->pcrypt_refs);
+
+ atomic_inc(&chan->vm->engref[engine]);
+ chan->engctx[engine] = ctx;
return 0;
}
-void
-nv84_crypt_destroy_context(struct nouveau_channel *chan)
+static void
+nv84_crypt_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
u32 inst;
- if (!chan->crypt_ctx)
- return;
-
inst = (chan->ramin->vinst >> 12);
inst |= 0x80000000;
@@ -80,43 +82,39 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
nv_wr32(dev, 0x10200c, 0x00000010);
- nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
- atomic_dec(&chan->vm->pcrypt_refs);
-}
+ nouveau_gpuobj_ref(NULL, &ctx);
-void
-nv84_crypt_tlb_flush(struct drm_device *dev)
-{
- nv50_vm_flush_engine(dev, 0x0a);
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = NULL;
}
-int
-nv84_crypt_init(struct drm_device *dev)
+static int
+nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
-
- if (!pcrypt->registered) {
- NVOBJ_CLASS(dev, 0x74c1, CRYPT);
- pcrypt->registered = true;
- }
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
- nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
- nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 5;
+ obj->class = class;
- nouveau_irq_register(dev, 14, nv84_crypt_isr);
- nv_wr32(dev, 0x102130, 0xffffffff);
- nv_wr32(dev, 0x102140, 0xffffffbf);
+ nv_wo32(obj, 0x00, class);
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, 0x10200c, 0x00000010);
- return 0;
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
}
-void
-nv84_crypt_fini(struct drm_device *dev)
+static void
+nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
{
- nv_wr32(dev, 0x102140, 0x00000000);
- nouveau_irq_unregister(dev, 14);
+ nv50_vm_flush_engine(dev, 0x0a);
}
static void
@@ -138,3 +136,58 @@ nv84_crypt_isr(struct drm_device *dev)
nv50_fb_vm_trap(dev, show);
}
+
+static int
+nv84_crypt_fini(struct drm_device *dev, int engine)
+{
+ nv_wr32(dev, 0x102140, 0x00000000);
+ return 0;
+}
+
+static int
+nv84_crypt_init(struct drm_device *dev, int engine)
+{
+ nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+
+ nv_wr32(dev, 0x102130, 0xffffffff);
+ nv_wr32(dev, 0x102140, 0xffffffbf);
+
+ nv_wr32(dev, 0x10200c, 0x00000010);
+ return 0;
+}
+
+static void
+nv84_crypt_destroy(struct drm_device *dev, int engine)
+{
+ struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
+
+ NVOBJ_ENGINE_DEL(dev, CRYPT);
+
+ nouveau_irq_unregister(dev, 14);
+ kfree(pcrypt);
+}
+
+int
+nv84_crypt_create(struct drm_device *dev)
+{
+ struct nv84_crypt_engine *pcrypt;
+
+ pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
+ if (!pcrypt)
+ return -ENOMEM;
+
+ pcrypt->base.destroy = nv84_crypt_destroy;
+ pcrypt->base.init = nv84_crypt_init;
+ pcrypt->base.fini = nv84_crypt_fini;
+ pcrypt->base.context_new = nv84_crypt_context_new;
+ pcrypt->base.context_del = nv84_crypt_context_del;
+ pcrypt->base.object_new = nv84_crypt_object_new;
+ pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
+
+ nouveau_irq_register(dev, 14, nv84_crypt_isr);
+
+ NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
+ NVOBJ_CLASS (dev, 0x74c1, CRYPT);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
new file mode 100644
index 000000000000..b86820a61220
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nva3_copy.c
@@ -0,0 +1,226 @@
+/*
+ * 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
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nva3_copy.fuc.h"
+
+struct nva3_copy_engine {
+ struct nouveau_exec_engine base;
+};
+
+static int
+nva3_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx = NULL;
+ int ret;
+
+ NV_DEBUG(dev, "ch%d\n", chan->id);
+
+ ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ramin, 0xc0, 0x00190000);
+ nv_wo32(ramin, 0xc4, ctx->vinst + ctx->size - 1);
+ nv_wo32(ramin, 0xc8, ctx->vinst);
+ nv_wo32(ramin, 0xcc, 0x00000000);
+ nv_wo32(ramin, 0xd0, 0x00000000);
+ nv_wo32(ramin, 0xd4, 0x00000000);
+ dev_priv->engine.instmem.flush(dev);
+
+ atomic_inc(&chan->vm->engref[engine]);
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static int
+nva3_copy_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+
+ /* fuc engine doesn't need an object, our ramht code does.. */
+ ctx->engine = 3;
+ ctx->class = class;
+ return nouveau_ramht_insert(chan, handle, ctx);
+}
+
+static void
+nva3_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ u32 inst;
+
+ inst = (chan->ramin->vinst >> 12);
+ inst |= 0x40000000;
+
+ /* disable fifo access */
+ nv_wr32(dev, 0x104048, 0x00000000);
+ /* mark channel as unloaded if it's currently active */
+ if (nv_rd32(dev, 0x104050) == inst)
+ nv_mask(dev, 0x104050, 0x40000000, 0x00000000);
+ /* mark next channel as invalid if it's about to be loaded */
+ if (nv_rd32(dev, 0x104054) == inst)
+ nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+ /* restore fifo access */
+ nv_wr32(dev, 0x104048, 0x00000003);
+
+ for (inst = 0xc0; inst <= 0xd4; inst += 4)
+ nv_wo32(chan->ramin, inst, 0x00000000);
+
+ nouveau_gpuobj_ref(NULL, &ctx);
+
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = ctx;
+}
+
+static void
+nva3_copy_tlb_flush(struct drm_device *dev, int engine)
+{
+ nv50_vm_flush_engine(dev, 0x0d);
+}
+
+static int
+nva3_copy_init(struct drm_device *dev, int engine)
+{
+ int i;
+
+ nv_mask(dev, 0x000200, 0x00002000, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00002000, 0x00002000);
+ nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */
+
+ /* upload ucode */
+ nv_wr32(dev, 0x1041c0, 0x01000000);
+ for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
+ nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]);
+
+ nv_wr32(dev, 0x104180, 0x01000000);
+ for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(dev, 0x104188, i >> 6);
+ nv_wr32(dev, 0x104184, nva3_pcopy_code[i]);
+ }
+
+ /* start it running */
+ nv_wr32(dev, 0x10410c, 0x00000000);
+ nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */
+ nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */
+ return 0;
+}
+
+static int
+nva3_copy_fini(struct drm_device *dev, int engine)
+{
+ nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
+
+ /* trigger fuc context unload */
+ nv_wait(dev, 0x104008, 0x0000000c, 0x00000000);
+ nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+ nv_wr32(dev, 0x104000, 0x00000008);
+ nv_wait(dev, 0x104008, 0x00000008, 0x00000000);
+
+ nv_wr32(dev, 0x104014, 0xffffffff);
+ return 0;
+}
+
+static struct nouveau_enum nva3_copy_isr_error_name[] = {
+ { 0x0001, "ILLEGAL_MTHD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "INVALID_BITFIELD" },
+ {}
+};
+
+static void
+nva3_copy_isr(struct drm_device *dev)
+{
+ u32 dispatch = nv_rd32(dev, 0x10401c);
+ u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16);
+ u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff;
+ u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff;
+ u32 addr = nv_rd32(dev, 0x104040) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_rd32(dev, 0x104044);
+ int chid = nv50_graph_isr_chid(dev, inst);
+
+ if (stat & 0x00000040) {
+ NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+ nouveau_enum_print(nva3_copy_isr_error_name, ssta);
+ printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, mthd, data);
+ nv_wr32(dev, 0x104004, 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+ nv_wr32(dev, 0x104004, stat);
+ }
+ nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nva3_copy_destroy(struct drm_device *dev, int engine)
+{
+ struct nva3_copy_engine *pcopy = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 22);
+
+ NVOBJ_ENGINE_DEL(dev, COPY0);
+ kfree(pcopy);
+}
+
+int
+nva3_copy_create(struct drm_device *dev)
+{
+ struct nva3_copy_engine *pcopy;
+
+ pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+ if (!pcopy)
+ return -ENOMEM;
+
+ pcopy->base.destroy = nva3_copy_destroy;
+ pcopy->base.init = nva3_copy_init;
+ pcopy->base.fini = nva3_copy_fini;
+ pcopy->base.context_new = nva3_copy_context_new;
+ pcopy->base.context_del = nva3_copy_context_del;
+ pcopy->base.object_new = nva3_copy_object_new;
+ pcopy->base.tlb_flush = nva3_copy_tlb_flush;
+
+ nouveau_irq_register(dev, 22, nva3_copy_isr);
+
+ NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+ NVOBJ_CLASS(dev, 0x85b5, COPY0);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc b/drivers/gpu/drm/nouveau/nva3_copy.fuc
new file mode 100644
index 000000000000..eaf35f8321ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nva3_copy.fuc
@@ -0,0 +1,870 @@
+/* fuc microcode for copy engine on nva3- chipsets
+ *
+ * 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 for nva3:nvc0
+ * m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
+ *
+ * To build for nvc0-
+ * m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
+ */
+
+ifdef(`NVA3',
+.section nva3_pcopy_data,
+.section nvc0_pcopy_data
+)
+
+ctx_object: .b32 0
+ifdef(`NVA3',
+ctx_dma:
+ctx_dma_query: .b32 0
+ctx_dma_src: .b32 0
+ctx_dma_dst: .b32 0
+,)
+.equ ctx_dma_count 3
+ctx_query_address_high: .b32 0
+ctx_query_address_low: .b32 0
+ctx_query_counter: .b32 0
+ctx_src_address_high: .b32 0
+ctx_src_address_low: .b32 0
+ctx_src_pitch: .b32 0
+ctx_src_tile_mode: .b32 0
+ctx_src_xsize: .b32 0
+ctx_src_ysize: .b32 0
+ctx_src_zsize: .b32 0
+ctx_src_zoff: .b32 0
+ctx_src_xoff: .b32 0
+ctx_src_yoff: .b32 0
+ctx_src_cpp: .b32 0
+ctx_dst_address_high: .b32 0
+ctx_dst_address_low: .b32 0
+ctx_dst_pitch: .b32 0
+ctx_dst_tile_mode: .b32 0
+ctx_dst_xsize: .b32 0
+ctx_dst_ysize: .b32 0
+ctx_dst_zsize: .b32 0
+ctx_dst_zoff: .b32 0
+ctx_dst_xoff: .b32 0
+ctx_dst_yoff: .b32 0
+ctx_dst_cpp: .b32 0
+ctx_format: .b32 0
+ctx_swz_const0: .b32 0
+ctx_swz_const1: .b32 0
+ctx_xcnt: .b32 0
+ctx_ycnt: .b32 0
+.align 256
+
+dispatch_table:
+// mthd 0x0000, NAME
+.b16 0x000 1
+.b32 ctx_object ~0xffffffff
+// mthd 0x0100, NOP
+.b16 0x040 1
+.b32 0x00010000 + cmd_nop ~0xffffffff
+// mthd 0x0140, PM_TRIGGER
+.b16 0x050 1
+.b32 0x00010000 + cmd_pm_trigger ~0xffffffff
+ifdef(`NVA3', `
+// mthd 0x0180-0x018c, DMA_
+.b16 0x060 ctx_dma_count
+dispatch_dma:
+.b32 0x00010000 + cmd_dma ~0xffffffff
+.b32 0x00010000 + cmd_dma ~0xffffffff
+.b32 0x00010000 + cmd_dma ~0xffffffff
+',)
+// mthd 0x0200-0x0218, SRC_TILE
+.b16 0x80 7
+.b32 ctx_src_tile_mode ~0x00000fff
+.b32 ctx_src_xsize ~0x0007ffff
+.b32 ctx_src_ysize ~0x00001fff
+.b32 ctx_src_zsize ~0x000007ff
+.b32 ctx_src_zoff ~0x00000fff
+.b32 ctx_src_xoff ~0x0007ffff
+.b32 ctx_src_yoff ~0x00001fff
+// mthd 0x0220-0x0238, DST_TILE
+.b16 0x88 7
+.b32 ctx_dst_tile_mode ~0x00000fff
+.b32 ctx_dst_xsize ~0x0007ffff
+.b32 ctx_dst_ysize ~0x00001fff
+.b32 ctx_dst_zsize ~0x000007ff
+.b32 ctx_dst_zoff ~0x00000fff
+.b32 ctx_dst_xoff ~0x0007ffff
+.b32 ctx_dst_yoff ~0x00001fff
+// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
+.b16 0xc0 2
+.b32 0x00010000 + cmd_exec ~0xffffffff
+.b32 0x00010000 + cmd_wrcache_flush ~0xffffffff
+// mthd 0x030c-0x0340, various stuff
+.b16 0xc3 14
+.b32 ctx_src_address_high ~0x000000ff
+.b32 ctx_src_address_low ~0xfffffff0
+.b32 ctx_dst_address_high ~0x000000ff
+.b32 ctx_dst_address_low ~0xfffffff0
+.b32 ctx_src_pitch ~0x0007ffff
+.b32 ctx_dst_pitch ~0x0007ffff
+.b32 ctx_xcnt ~0x0000ffff
+.b32 ctx_ycnt ~0x00001fff
+.b32 ctx_format ~0x0333ffff
+.b32 ctx_swz_const0 ~0xffffffff
+.b32 ctx_swz_const1 ~0xffffffff
+.b32 ctx_query_address_high ~0x000000ff
+.b32 ctx_query_address_low ~0xffffffff
+.b32 ctx_query_counter ~0xffffffff
+.b16 0x800 0
+
+ifdef(`NVA3',
+.section nva3_pcopy_code,
+.section nvc0_pcopy_code
+)
+
+main:
+ clear b32 $r0
+ mov $sp $r0
+
+ // setup i0 handler and route fifo and ctxswitch to it
+ mov $r1 ih
+ mov $iv0 $r1
+ mov $r1 0x400
+ movw $r2 0xfff3
+ sethi $r2 0
+ iowr I[$r2 + 0x300] $r2
+
+ // enable interrupts
+ or $r2 0xc
+ iowr I[$r1] $r2
+ bset $flags ie0
+
+ // enable fifo access and context switching
+ mov $r1 0x1200
+ mov $r2 3
+ iowr I[$r1] $r2
+
+ // sleep forever, waking for interrupts
+ bset $flags $p0
+ spin:
+ sleep $p0
+ bra spin
+
+// i0 handler
+ih:
+ iord $r1 I[$r0 + 0x200]
+
+ and $r2 $r1 0x00000008
+ bra e ih_no_chsw
+ call chsw
+ ih_no_chsw:
+ and $r2 $r1 0x00000004
+ bra e ih_no_cmd
+ call dispatch
+
+ ih_no_cmd:
+ and $r1 $r1 0x0000000c
+ iowr I[$r0 + 0x100] $r1
+ iret
+
+// $p1 direction (0 = unload, 1 = load)
+// $r3 channel
+swctx:
+ mov $r4 0x7700
+ mov $xtargets $r4
+ifdef(`NVA3', `
+ // target 7 hardcoded to ctx dma object
+ mov $xdbase $r0
+', ` // NVC0
+ // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
+ mov $r4 0x2100
+ iord $r4 I[$r4 + 0]
+ and $r4 1
+ shl b32 $r4 4
+ add b32 $r4 0x30
+
+ // channel is in vram
+ mov $r15 0x61c
+ shl b32 $r15 6
+ mov $r5 0x114
+ iowrs I[$r15] $r5
+
+ // read 16-byte PCOPYn info, containing context pointer, from channel
+ shl b32 $r5 $r3 4
+ add b32 $r5 2
+ mov $xdbase $r5
+ mov $r5 $sp
+ // get a chunk of stack space, aligned to 256 byte boundary
+ sub b32 $r5 0x100
+ mov $r6 0xff
+ not b32 $r6
+ and $r5 $r6
+ sethi $r5 0x00020000
+ xdld $r4 $r5
+ xdwait
+ sethi $r5 0
+
+ // set context pointer, from within channel VM
+ mov $r14 0
+ iowrs I[$r15] $r14
+ ld b32 $r4 D[$r5 + 0]
+ shr b32 $r4 8
+ ld b32 $r6 D[$r5 + 4]
+ shl b32 $r6 24
+ or $r4 $r6
+ mov $xdbase $r4
+')
+ // 256-byte context, at start of data segment
+ mov b32 $r4 $r0
+ sethi $r4 0x60000
+
+ // swap!
+ bra $p1 swctx_load
+ xdst $r0 $r4
+ bra swctx_done
+ swctx_load:
+ xdld $r0 $r4
+ swctx_done:
+ xdwait
+ ret
+
+chsw:
+ // read current channel
+ mov $r2 0x1400
+ iord $r3 I[$r2]
+
+ // if it's active, unload it and return
+ xbit $r15 $r3 0x1e
+ bra e chsw_no_unload
+ bclr $flags $p1
+ call swctx
+ bclr $r3 0x1e
+ iowr I[$r2] $r3
+ mov $r4 1
+ iowr I[$r2 + 0x200] $r4
+ ret
+
+ // read next channel
+ chsw_no_unload:
+ iord $r3 I[$r2 + 0x100]
+
+ // is there a channel waiting to be loaded?
+ xbit $r13 $r3 0x1e
+ bra e chsw_finish_load
+ bset $flags $p1
+ call swctx
+ifdef(`NVA3',
+ // load dma objects back into TARGET regs
+ mov $r5 ctx_dma
+ mov $r6 ctx_dma_count
+ chsw_load_ctx_dma:
+ ld b32 $r7 D[$r5 + $r6 * 4]
+ add b32 $r8 $r6 0x180
+ shl b32 $r8 8
+ iowr I[$r8] $r7
+ sub b32 $r6 1
+ bra nc chsw_load_ctx_dma
+,)
+
+ chsw_finish_load:
+ mov $r3 2
+ iowr I[$r2 + 0x200] $r3
+ ret
+
+dispatch:
+ // read incoming fifo command
+ mov $r3 0x1900
+ iord $r2 I[$r3 + 0x100]
+ iord $r3 I[$r3 + 0x000]
+ and $r4 $r2 0x7ff
+ // $r2 will be used to store exception data
+ shl b32 $r2 0x10
+
+ // lookup method in the dispatch table, ILLEGAL_MTHD if not found
+ mov $r5 dispatch_table
+ clear b32 $r6
+ clear b32 $r7
+ dispatch_loop:
+ ld b16 $r6 D[$r5 + 0]
+ ld b16 $r7 D[$r5 + 2]
+ add b32 $r5 4
+ cmpu b32 $r4 $r6
+ bra c dispatch_illegal_mthd
+ add b32 $r7 $r6
+ cmpu b32 $r4 $r7
+ bra c dispatch_valid_mthd
+ sub b32 $r7 $r6
+ shl b32 $r7 3
+ add b32 $r5 $r7
+ bra dispatch_loop
+
+ // ensure no bits set in reserved fields, INVALID_BITFIELD
+ dispatch_valid_mthd:
+ sub b32 $r4 $r6
+ shl b32 $r4 3
+ add b32 $r4 $r5
+ ld b32 $r5 D[$r4 + 4]
+ and $r5 $r3
+ cmpu b32 $r5 0
+ bra ne dispatch_invalid_bitfield
+
+ // depending on dispatch flags: execute method, or save data as state
+ ld b16 $r5 D[$r4 + 0]
+ ld b16 $r6 D[$r4 + 2]
+ cmpu b32 $r6 0
+ bra ne dispatch_cmd
+ st b32 D[$r5] $r3
+ bra dispatch_done
+ dispatch_cmd:
+ bclr $flags $p1
+ call $r5
+ bra $p1 dispatch_error
+ bra dispatch_done
+
+ dispatch_invalid_bitfield:
+ or $r2 2
+ dispatch_illegal_mthd:
+ or $r2 1
+
+ // store exception data in SCRATCH0/SCRATCH1, signal hostirq
+ dispatch_error:
+ mov $r4 0x1000
+ iowr I[$r4 + 0x000] $r2
+ iowr I[$r4 + 0x100] $r3
+ mov $r2 0x40
+ iowr I[$r0] $r2
+ hostirq_wait:
+ iord $r2 I[$r0 + 0x200]
+ and $r2 0x40
+ cmpu b32 $r2 0
+ bra ne hostirq_wait
+
+ dispatch_done:
+ mov $r2 0x1d00
+ mov $r3 1
+ iowr I[$r2] $r3
+ ret
+
+// No-operation
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_nop:
+ ret
+
+// PM_TRIGGER
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_pm_trigger:
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x20000
+ iowr I[$r2] $r3
+ ret
+
+ifdef(`NVA3',
+// SET_DMA_* method handler
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_dma:
+ sub b32 $r4 dispatch_dma
+ shr b32 $r4 1
+ bset $r3 0x1e
+ st b32 D[$r4 + ctx_dma] $r3
+ add b32 $r4 0x600
+ shl b32 $r4 6
+ iowr I[$r4] $r3
+ ret
+,)
+
+// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
+//
+cmd_exec_set_format:
+ // zero out a chunk of the stack to store the swizzle into
+ add $sp -0x10
+ st b32 D[$sp + 0x00] $r0
+ st b32 D[$sp + 0x04] $r0
+ st b32 D[$sp + 0x08] $r0
+ st b32 D[$sp + 0x0c] $r0
+
+ // extract cpp, src_ncomp and dst_ncomp from FORMAT
+ ld b32 $r4 D[$r0 + ctx_format]
+ extr $r5 $r4 16:17
+ add b32 $r5 1
+ extr $r6 $r4 20:21
+ add b32 $r6 1
+ extr $r7 $r4 24:25
+ add b32 $r7 1
+
+ // convert FORMAT swizzle mask to hw swizzle mask
+ bclr $flags $p2
+ clear b32 $r8
+ clear b32 $r9
+ ncomp_loop:
+ and $r10 $r4 0xf
+ shr b32 $r4 4
+ clear b32 $r11
+ bpc_loop:
+ cmpu b8 $r10 4
+ bra nc cmp_c0
+ mulu $r12 $r10 $r5
+ add b32 $r12 $r11
+ bset $flags $p2
+ bra bpc_next
+ cmp_c0:
+ bra ne cmp_c1
+ mov $r12 0x10
+ add b32 $r12 $r11
+ bra bpc_next
+ cmp_c1:
+ cmpu b8 $r10 6
+ bra nc cmp_zero
+ mov $r12 0x14
+ add b32 $r12 $r11
+ bra bpc_next
+ cmp_zero:
+ mov $r12 0x80
+ bpc_next:
+ st b8 D[$sp + $r8] $r12
+ add b32 $r8 1
+ add b32 $r11 1
+ cmpu b32 $r11 $r5
+ bra c bpc_loop
+ add b32 $r9 1
+ cmpu b32 $r9 $r7
+ bra c ncomp_loop
+
+ // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
+ mulu $r6 $r5
+ st b32 D[$r0 + ctx_src_cpp] $r6
+ ld b32 $r8 D[$r0 + ctx_xcnt]
+ mulu $r6 $r8
+ bra $p2 dst_xcnt
+ clear b32 $r6
+
+ dst_xcnt:
+ mulu $r7 $r5
+ st b32 D[$r0 + ctx_dst_cpp] $r7
+ mulu $r7 $r8
+
+ mov $r5 0x810
+ shl b32 $r5 6
+ iowr I[$r5 + 0x000] $r6
+ iowr I[$r5 + 0x100] $r7
+ add b32 $r5 0x800
+ ld b32 $r6 D[$r0 + ctx_dst_cpp]
+ sub b32 $r6 1
+ shl b32 $r6 8
+ ld b32 $r7 D[$r0 + ctx_src_cpp]
+ sub b32 $r7 1
+ or $r6 $r7
+ iowr I[$r5 + 0x000] $r6
+ add b32 $r5 0x100
+ ld b32 $r6 D[$sp + 0x00]
+ iowr I[$r5 + 0x000] $r6
+ ld b32 $r6 D[$sp + 0x04]
+ iowr I[$r5 + 0x100] $r6
+ ld b32 $r6 D[$sp + 0x08]
+ iowr I[$r5 + 0x200] $r6
+ ld b32 $r6 D[$sp + 0x0c]
+ iowr I[$r5 + 0x300] $r6
+ add b32 $r5 0x400
+ ld b32 $r6 D[$r0 + ctx_swz_const0]
+ iowr I[$r5 + 0x000] $r6
+ ld b32 $r6 D[$r0 + ctx_swz_const1]
+ iowr I[$r5 + 0x100] $r6
+ add $sp 0x10
+ ret
+
+// Setup to handle a tiled surface
+//
+// Calculates a number of parameters the hardware requires in order
+// to correctly handle tiling.
+//
+// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
+// nTx = round_up(w * cpp, 1 << Tp) >> Tp
+// nTy = round_up(h, 1 << Th) >> Th
+// Txo = (x * cpp) & ((1 << Tp) - 1)
+// Tx = (x * cpp) >> Tp
+// Tyo = y & ((1 << Th) - 1)
+// Ty = y >> Th
+// Tzo = z & ((1 << Td) - 1)
+// Tz = z >> Td
+//
+// off = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
+// off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
+//
+// Inputs:
+// $r4: hw command (0x104800)
+// $r5: ctx offset adjustment for src/dst selection
+// $p2: set if dst surface
+//
+cmd_exec_set_surface_tiled:
+ // translate TILE_MODE into Tp, Th, Td shift values
+ ld b32 $r7 D[$r5 + ctx_src_tile_mode]
+ extr $r9 $r7 8:11
+ extr $r8 $r7 4:7
+ifdef(`NVA3',
+ add b32 $r8 2
+,
+ add b32 $r8 3
+)
+ extr $r7 $r7 0:3
+ cmp b32 $r7 0xe
+ bra ne xtile64
+ mov $r7 4
+ bra xtileok
+ xtile64:
+ xbit $r7 $flags $p2
+ add b32 $r7 17
+ bset $r4 $r7
+ mov $r7 6
+ xtileok:
+
+ // Op = (x * cpp) & ((1 << Tp) - 1)
+ // Tx = (x * cpp) >> Tp
+ ld b32 $r10 D[$r5 + ctx_src_xoff]
+ ld b32 $r11 D[$r5 + ctx_src_cpp]
+ mulu $r10 $r11
+ mov $r11 1
+ shl b32 $r11 $r7
+ sub b32 $r11 1
+ and $r12 $r10 $r11
+ shr b32 $r10 $r7
+
+ // Tyo = y & ((1 << Th) - 1)
+ // Ty = y >> Th
+ ld b32 $r13 D[$r5 + ctx_src_yoff]
+ mov $r14 1
+ shl b32 $r14 $r8
+ sub b32 $r14 1
+ and $r11 $r13 $r14
+ shr b32 $r13 $r8
+
+ // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
+ add b32 $r14 1
+ shl b32 $r15 $r14 12
+ sub b32 $r14 $r11
+ or $r15 $r14
+ xbit $r6 $flags $p2
+ add b32 $r6 0x208
+ shl b32 $r6 8
+ iowr I[$r6 + 0x000] $r15
+
+ // Op += Tyo << Tp
+ shl b32 $r11 $r7
+ add b32 $r12 $r11
+
+ // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
+ ld b32 $r15 D[$r5 + ctx_src_xsize]
+ ld b32 $r11 D[$r5 + ctx_src_cpp]
+ mulu $r15 $r11
+ mov $r11 1
+ shl b32 $r11 $r7
+ sub b32 $r11 1
+ add b32 $r15 $r11
+ shr b32 $r15 $r7
+ push $r15
+
+ // nTy = (h + ((1 << Th) - 1)) >> Th
+ ld b32 $r15 D[$r5 + ctx_src_ysize]
+ mov $r11 1
+ shl b32 $r11 $r8
+ sub b32 $r11 1
+ add b32 $r15 $r11
+ shr b32 $r15 $r8
+ push $r15
+
+ // Tys = Tp + Th
+ // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
+ add b32 $r7 $r8
+ sub b32 $r8 2
+ mov $r11 1
+ shl b32 $r11 $r8
+ shl b32 $r11 $r9
+
+ // Tzo = z & ((1 << Td) - 1)
+ // Tz = z >> Td
+ // Op += Tzo << Tys
+ // Ts = Tys + Td
+ ld b32 $r8 D[$r5 + ctx_src_zoff]
+ mov $r14 1
+ shl b32 $r14 $r9
+ sub b32 $r14 1
+ and $r15 $r8 $r14
+ shl b32 $r15 $r7
+ add b32 $r12 $r15
+ add b32 $r7 $r9
+ shr b32 $r8 $r9
+
+ // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
+ pop $r15
+ pop $r9
+ mulu $r13 $r9
+ add b32 $r10 $r13
+ mulu $r8 $r9
+ mulu $r8 $r15
+ add b32 $r10 $r8
+ shl b32 $r10 $r7
+
+ // PITCH = (nTx - 1) << Ts
+ sub b32 $r9 1
+ shl b32 $r9 $r7
+ iowr I[$r6 + 0x200] $r9
+
+ // SRC_ADDRESS_LOW = (Ot + Op) & 0xffffffff
+ // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
+ ld b32 $r7 D[$r5 + ctx_src_address_low]
+ ld b32 $r8 D[$r5 + ctx_src_address_high]
+ add b32 $r10 $r12
+ add b32 $r7 $r10
+ adc b32 $r8 0
+ shl b32 $r8 16
+ or $r8 $r11
+ sub b32 $r6 0x600
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ iowr I[$r6 + 0x000] $r8
+ ret
+
+// Setup to handle a linear surface
+//
+// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
+//
+cmd_exec_set_surface_linear:
+ xbit $r6 $flags $p2
+ add b32 $r6 0x202
+ shl b32 $r6 8
+ ld b32 $r7 D[$r5 + ctx_src_address_low]
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ ld b32 $r7 D[$r5 + ctx_src_address_high]
+ shl b32 $r7 16
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ ld b32 $r7 D[$r5 + ctx_src_pitch]
+ iowr I[$r6 + 0x000] $r7
+ ret
+
+// wait for regs to be available for use
+cmd_exec_wait:
+ push $r0
+ push $r1
+ mov $r0 0x800
+ shl b32 $r0 6
+ loop:
+ iord $r1 I[$r0]
+ and $r1 1
+ bra ne loop
+ pop $r1
+ pop $r0
+ ret
+
+cmd_exec_query:
+ // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
+ xbit $r4 $r3 13
+ bra ne query_counter
+ call cmd_exec_wait
+ mov $r4 0x80c
+ shl b32 $r4 6
+ ld b32 $r5 D[$r0 + ctx_query_address_low]
+ add b32 $r5 4
+ iowr I[$r4 + 0x000] $r5
+ iowr I[$r4 + 0x100] $r0
+ mov $r5 0xc
+ iowr I[$r4 + 0x200] $r5
+ add b32 $r4 0x400
+ ld b32 $r5 D[$r0 + ctx_query_address_high]
+ shl b32 $r5 16
+ iowr I[$r4 + 0x000] $r5
+ add b32 $r4 0x500
+ mov $r5 0x00000b00
+ sethi $r5 0x00010000
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00004040
+ shl b32 $r5 1
+ sethi $r5 0x80800000
+ iowr I[$r4 + 0x100] $r5
+ mov $r5 0x00001110
+ sethi $r5 0x13120000
+ iowr I[$r4 + 0x200] $r5
+ mov $r5 0x00001514
+ sethi $r5 0x17160000
+ iowr I[$r4 + 0x300] $r5
+ mov $r5 0x00002601
+ sethi $r5 0x00010000
+ mov $r4 0x800
+ shl b32 $r4 6
+ iowr I[$r4 + 0x000] $r5
+
+ // write COUNTER
+ query_counter:
+ call cmd_exec_wait
+ mov $r4 0x80c
+ shl b32 $r4 6
+ ld b32 $r5 D[$r0 + ctx_query_address_low]
+ iowr I[$r4 + 0x000] $r5
+ iowr I[$r4 + 0x100] $r0
+ mov $r5 0x4
+ iowr I[$r4 + 0x200] $r5
+ add b32 $r4 0x400
+ ld b32 $r5 D[$r0 + ctx_query_address_high]
+ shl b32 $r5 16
+ iowr I[$r4 + 0x000] $r5
+ add b32 $r4 0x500
+ mov $r5 0x00000300
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00001110
+ sethi $r5 0x13120000
+ iowr I[$r4 + 0x100] $r5
+ ld b32 $r5 D[$r0 + ctx_query_counter]
+ add b32 $r4 0x500
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00002601
+ sethi $r5 0x00010000
+ mov $r4 0x800
+ shl b32 $r4 6
+ iowr I[$r4 + 0x000] $r5
+ ret
+
+// Execute a copy operation
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// 000002000 QUERY_SHORT
+// 000001000 QUERY
+// 000000100 DST_LINEAR
+// 000000010 SRC_LINEAR
+// 000000001 FORMAT
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_exec:
+ call cmd_exec_wait
+
+ // if format requested, call function to calculate it, otherwise
+ // fill in cpp/xcnt for both surfaces as if (cpp == 1)
+ xbit $r15 $r3 0
+ bra e cmd_exec_no_format
+ call cmd_exec_set_format
+ mov $r4 0x200
+ bra cmd_exec_init_src_surface
+ cmd_exec_no_format:
+ mov $r6 0x810
+ shl b32 $r6 6
+ mov $r7 1
+ st b32 D[$r0 + ctx_src_cpp] $r7
+ st b32 D[$r0 + ctx_dst_cpp] $r7
+ ld b32 $r7 D[$r0 + ctx_xcnt]
+ iowr I[$r6 + 0x000] $r7
+ iowr I[$r6 + 0x100] $r7
+ clear b32 $r4
+
+ cmd_exec_init_src_surface:
+ bclr $flags $p2
+ clear b32 $r5
+ xbit $r15 $r3 4
+ bra e src_tiled
+ call cmd_exec_set_surface_linear
+ bra cmd_exec_init_dst_surface
+ src_tiled:
+ call cmd_exec_set_surface_tiled
+ bset $r4 7
+
+ cmd_exec_init_dst_surface:
+ bset $flags $p2
+ mov $r5 ctx_dst_address_high - ctx_src_address_high
+ xbit $r15 $r3 8
+ bra e dst_tiled
+ call cmd_exec_set_surface_linear
+ bra cmd_exec_kick
+ dst_tiled:
+ call cmd_exec_set_surface_tiled
+ bset $r4 8
+
+ cmd_exec_kick:
+ mov $r5 0x800
+ shl b32 $r5 6
+ ld b32 $r6 D[$r0 + ctx_ycnt]
+ iowr I[$r5 + 0x100] $r6
+ mov $r6 0x0041
+ // SRC_TARGET = 1, DST_TARGET = 2
+ sethi $r6 0x44000000
+ or $r4 $r6
+ iowr I[$r5] $r4
+
+ // if requested, queue up a QUERY write after the copy has completed
+ xbit $r15 $r3 12
+ bra e cmd_exec_done
+ call cmd_exec_query
+
+ cmd_exec_done:
+ ret
+
+// Flush write cache
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_wrcache_flush:
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x10000
+ iowr I[$r2] $r3
+ ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc.h b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h
new file mode 100644
index 000000000000..2731de22ebe9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h
@@ -0,0 +1,534 @@
+uint32_t nva3_pcopy_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,
+ 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,
+ 0x00010000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010040,
+ 0x00010160,
+ 0x00000000,
+ 0x00010050,
+ 0x00010162,
+ 0x00000000,
+ 0x00030060,
+ 0x00010170,
+ 0x00000000,
+ 0x00010170,
+ 0x00000000,
+ 0x00010170,
+ 0x00000000,
+ 0x00070080,
+ 0x00000028,
+ 0xfffff000,
+ 0x0000002c,
+ 0xfff80000,
+ 0x00000030,
+ 0xffffe000,
+ 0x00000034,
+ 0xfffff800,
+ 0x00000038,
+ 0xfffff000,
+ 0x0000003c,
+ 0xfff80000,
+ 0x00000040,
+ 0xffffe000,
+ 0x00070088,
+ 0x00000054,
+ 0xfffff000,
+ 0x00000058,
+ 0xfff80000,
+ 0x0000005c,
+ 0xffffe000,
+ 0x00000060,
+ 0xfffff800,
+ 0x00000064,
+ 0xfffff000,
+ 0x00000068,
+ 0xfff80000,
+ 0x0000006c,
+ 0xffffe000,
+ 0x000200c0,
+ 0x00010492,
+ 0x00000000,
+ 0x0001051b,
+ 0x00000000,
+ 0x000e00c3,
+ 0x0000001c,
+ 0xffffff00,
+ 0x00000020,
+ 0x0000000f,
+ 0x00000048,
+ 0xffffff00,
+ 0x0000004c,
+ 0x0000000f,
+ 0x00000024,
+ 0xfff80000,
+ 0x00000050,
+ 0xfff80000,
+ 0x00000080,
+ 0xffff0000,
+ 0x00000084,
+ 0xffffe000,
+ 0x00000074,
+ 0xfccc0000,
+ 0x00000078,
+ 0x00000000,
+ 0x0000007c,
+ 0x00000000,
+ 0x00000010,
+ 0xffffff00,
+ 0x00000014,
+ 0x00000000,
+ 0x00000018,
+ 0x00000000,
+ 0x00000800,
+};
+
+uint32_t nva3_pcopy_code[] = {
+ 0x04fe04bd,
+ 0x3517f000,
+ 0xf10010fe,
+ 0xf1040017,
+ 0xf0fff327,
+ 0x22d00023,
+ 0x0c25f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x27f01200,
+ 0x0012d003,
+ 0xf40031f4,
+ 0x0ef40028,
+ 0x8001cffd,
+ 0xf40812c4,
+ 0x21f4060b,
+ 0x0412c472,
+ 0xf4060bf4,
+ 0x11c4c321,
+ 0x4001d00c,
+ 0x47f101f8,
+ 0x4bfe7700,
+ 0x0007fe00,
+ 0xf00204b9,
+ 0x01f40643,
+ 0x0604fa09,
+ 0xfa060ef4,
+ 0x03f80504,
+ 0x27f100f8,
+ 0x23cf1400,
+ 0x1e3fc800,
+ 0xf4170bf4,
+ 0x21f40132,
+ 0x1e3af052,
+ 0xf00023d0,
+ 0x24d00147,
+ 0xcf00f880,
+ 0x3dc84023,
+ 0x220bf41e,
+ 0xf40131f4,
+ 0x57f05221,
+ 0x0367f004,
+ 0xa07856bc,
+ 0xb6018068,
+ 0x87d00884,
+ 0x0162b600,
+ 0xf0f018f4,
+ 0x23d00237,
+ 0xf100f880,
+ 0xcf190037,
+ 0x33cf4032,
+ 0xff24e400,
+ 0x1024b607,
+ 0x010057f1,
+ 0x74bd64bd,
+ 0x58005658,
+ 0x50b60157,
+ 0x0446b804,
+ 0xbb4d08f4,
+ 0x47b80076,
+ 0x0f08f404,
+ 0xb60276bb,
+ 0x57bb0374,
+ 0xdf0ef400,
+ 0xb60246bb,
+ 0x45bb0344,
+ 0x01459800,
+ 0xb00453fd,
+ 0x1bf40054,
+ 0x00455820,
+ 0xb0014658,
+ 0x1bf40064,
+ 0x00538009,
+ 0xf4300ef4,
+ 0x55f90132,
+ 0xf40c01f4,
+ 0x25f0250e,
+ 0x0125f002,
+ 0x100047f1,
+ 0xd00042d0,
+ 0x27f04043,
+ 0x0002d040,
+ 0xf08002cf,
+ 0x24b04024,
+ 0xf71bf400,
+ 0x1d0027f1,
+ 0xd00137f0,
+ 0x00f80023,
+ 0x27f100f8,
+ 0x34bd2200,
+ 0xd00233f0,
+ 0x00f80023,
+ 0x012842b7,
+ 0xf00145b6,
+ 0x43801e39,
+ 0x0040b701,
+ 0x0644b606,
+ 0xf80043d0,
+ 0xf030f400,
+ 0xb00001b0,
+ 0x01b00101,
+ 0x0301b002,
+ 0xc71d0498,
+ 0x50b63045,
+ 0x3446c701,
+ 0xc70160b6,
+ 0x70b63847,
+ 0x0232f401,
+ 0x94bd84bd,
+ 0xb60f4ac4,
+ 0xb4bd0445,
+ 0xf404a430,
+ 0xa5ff0f18,
+ 0x00cbbbc0,
+ 0xf40231f4,
+ 0x1bf4220e,
+ 0x10c7f00c,
+ 0xf400cbbb,
+ 0xa430160e,
+ 0x0c18f406,
+ 0xbb14c7f0,
+ 0x0ef400cb,
+ 0x80c7f107,
+ 0x01c83800,
+ 0xb60180b6,
+ 0xb5b801b0,
+ 0xc308f404,
+ 0xb80190b6,
+ 0x08f40497,
+ 0x0065fdb2,
+ 0x98110680,
+ 0x68fd2008,
+ 0x0502f400,
+ 0x75fd64bd,
+ 0x1c078000,
+ 0xf10078fd,
+ 0xb6081057,
+ 0x56d00654,
+ 0x4057d000,
+ 0x080050b7,
+ 0xb61c0698,
+ 0x64b60162,
+ 0x11079808,
+ 0xfd0172b6,
+ 0x56d00567,
+ 0x0050b700,
+ 0x0060b401,
+ 0xb40056d0,
+ 0x56d00160,
+ 0x0260b440,
+ 0xb48056d0,
+ 0x56d00360,
+ 0x0050b7c0,
+ 0x1e069804,
+ 0x980056d0,
+ 0x56d01f06,
+ 0x1030f440,
+ 0x579800f8,
+ 0x6879c70a,
+ 0xb66478c7,
+ 0x77c70280,
+ 0x0e76b060,
+ 0xf0091bf4,
+ 0x0ef40477,
+ 0x027cf00f,
+ 0xfd1170b6,
+ 0x77f00947,
+ 0x0f5a9806,
+ 0xfd115b98,
+ 0xb7f000ab,
+ 0x04b7bb01,
+ 0xff01b2b6,
+ 0xa7bbc4ab,
+ 0x105d9805,
+ 0xbb01e7f0,
+ 0xe2b604e8,
+ 0xb4deff01,
+ 0xb605d8bb,
+ 0xef9401e0,
+ 0x02ebbb0c,
+ 0xf005fefd,
+ 0x60b7026c,
+ 0x64b60208,
+ 0x006fd008,
+ 0xbb04b7bb,
+ 0x5f9800cb,
+ 0x115b980b,
+ 0xf000fbfd,
+ 0xb7bb01b7,
+ 0x01b2b604,
+ 0xbb00fbbb,
+ 0xf0f905f7,
+ 0xf00c5f98,
+ 0xb8bb01b7,
+ 0x01b2b604,
+ 0xbb00fbbb,
+ 0xf0f905f8,
+ 0xb60078bb,
+ 0xb7f00282,
+ 0x04b8bb01,
+ 0x9804b9bb,
+ 0xe7f00e58,
+ 0x04e9bb01,
+ 0xff01e2b6,
+ 0xf7bbf48e,
+ 0x00cfbb04,
+ 0xbb0079bb,
+ 0xf0fc0589,
+ 0xd9fd90fc,
+ 0x00adbb00,
+ 0xfd0089fd,
+ 0xa8bb008f,
+ 0x04a7bb00,
+ 0xbb0192b6,
+ 0x69d00497,
+ 0x08579880,
+ 0xbb075898,
+ 0x7abb00ac,
+ 0x0081b600,
+ 0xfd1084b6,
+ 0x62b7058b,
+ 0x67d00600,
+ 0x0060b700,
+ 0x0068d004,
+ 0x6cf000f8,
+ 0x0260b702,
+ 0x0864b602,
+ 0xd0085798,
+ 0x60b70067,
+ 0x57980400,
+ 0x1074b607,
+ 0xb70067d0,
+ 0x98040060,
+ 0x67d00957,
+ 0xf900f800,
+ 0xf110f900,
+ 0xb6080007,
+ 0x01cf0604,
+ 0x0114f000,
+ 0xfcfa1bf4,
+ 0xf800fc10,
+ 0x0d34c800,
+ 0xf5701bf4,
+ 0xf103ab21,
+ 0xb6080c47,
+ 0x05980644,
+ 0x0450b605,
+ 0xd00045d0,
+ 0x57f04040,
+ 0x8045d00c,
+ 0x040040b7,
+ 0xb6040598,
+ 0x45d01054,
+ 0x0040b700,
+ 0x0057f105,
+ 0x0153f00b,
+ 0xf10045d0,
+ 0xb6404057,
+ 0x53f10154,
+ 0x45d08080,
+ 0x1057f140,
+ 0x1253f111,
+ 0x8045d013,
+ 0x151457f1,
+ 0x171653f1,
+ 0xf1c045d0,
+ 0xf0260157,
+ 0x47f10153,
+ 0x44b60800,
+ 0x0045d006,
+ 0x03ab21f5,
+ 0x080c47f1,
+ 0x980644b6,
+ 0x45d00505,
+ 0x4040d000,
+ 0xd00457f0,
+ 0x40b78045,
+ 0x05980400,
+ 0x1054b604,
+ 0xb70045d0,
+ 0xf1050040,
+ 0xd0030057,
+ 0x57f10045,
+ 0x53f11110,
+ 0x45d01312,
+ 0x06059840,
+ 0x050040b7,
+ 0xf10045d0,
+ 0xf0260157,
+ 0x47f10153,
+ 0x44b60800,
+ 0x0045d006,
+ 0x21f500f8,
+ 0x3fc803ab,
+ 0x0e0bf400,
+ 0x018921f5,
+ 0x020047f1,
+ 0xf11e0ef4,
+ 0xb6081067,
+ 0x77f00664,
+ 0x11078001,
+ 0x981c0780,
+ 0x67d02007,
+ 0x4067d000,
+ 0x32f444bd,
+ 0xc854bd02,
+ 0x0bf4043f,
+ 0x8221f50a,
+ 0x0a0ef403,
+ 0x027621f5,
+ 0xf40749f0,
+ 0x57f00231,
+ 0x083fc82c,
+ 0xf50a0bf4,
+ 0xf4038221,
+ 0x21f50a0e,
+ 0x49f00276,
+ 0x0057f108,
+ 0x0654b608,
+ 0xd0210698,
+ 0x67f04056,
+ 0x0063f141,
+ 0x0546fd44,
+ 0xc80054d0,
+ 0x0bf40c3f,
+ 0xc521f507,
+ 0xf100f803,
+ 0xbd220027,
+ 0x0133f034,
+ 0xf80023d0,
+ 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,
+};
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
index dbbafed36406..e4b2b9e934b2 100644
--- a/drivers/gpu/drm/nouveau/nva3_pm.c
+++ b/drivers/gpu/drm/nouveau/nva3_pm.c
@@ -27,32 +27,74 @@
#include "nouveau_bios.h"
#include "nouveau_pm.h"
-/*XXX: boards using limits 0x40 need fixing, the register layout
- * is correct here, but, there's some other funny magic
- * that modifies things, so it's not likely we'll set/read
- * the correct timings yet.. working on it...
+/* This is actually a lot more complex than it appears here, but hopefully
+ * this should be able to deal with what the VBIOS leaves for us..
+ *
+ * If not, well, I'll jump off that bridge when I come to it.
*/
struct nva3_pm_state {
- struct pll_lims pll;
- int N, M, P;
+ enum pll_types type;
+ u32 src0;
+ u32 src1;
+ u32 ctrl;
+ u32 coef;
+ u32 old_pnm;
+ u32 new_pnm;
+ u32 new_div;
};
+static int
+nva3_pm_pll_offset(u32 id)
+{
+ static const u32 pll_map[] = {
+ 0x00, PLL_CORE,
+ 0x01, PLL_SHADER,
+ 0x02, PLL_MEMORY,
+ 0x00, 0x00
+ };
+ const u32 *map = pll_map;
+
+ while (map[1]) {
+ if (id == map[1])
+ return map[0];
+ map += 2;
+ }
+
+ return -ENOENT;
+}
+
int
nva3_pm_clock_get(struct drm_device *dev, u32 id)
{
+ u32 src0, src1, ctrl, coef;
struct pll_lims pll;
- int P, N, M, ret;
- u32 reg;
+ int ret, off;
+ int P, N, M;
ret = get_pll_limits(dev, id, &pll);
if (ret)
return ret;
- reg = nv_rd32(dev, pll.reg + 4);
- P = (reg & 0x003f0000) >> 16;
- N = (reg & 0x0000ff00) >> 8;
- M = (reg & 0x000000ff);
+ off = nva3_pm_pll_offset(id);
+ if (off < 0)
+ return off;
+
+ src0 = nv_rd32(dev, 0x4120 + (off * 4));
+ src1 = nv_rd32(dev, 0x4160 + (off * 4));
+ ctrl = nv_rd32(dev, pll.reg + 0);
+ coef = nv_rd32(dev, pll.reg + 4);
+ NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ id, src0, src1, ctrl, coef);
+
+ if (ctrl & 0x00000008) {
+ u32 div = ((src1 & 0x003c0000) >> 18) + 1;
+ return (pll.refclk * 2) / div;
+ }
+
+ P = (coef & 0x003f0000) >> 16;
+ N = (coef & 0x0000ff00) >> 8;
+ M = (coef & 0x000000ff);
return pll.refclk * N / M / P;
}
@@ -60,36 +102,103 @@ void *
nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
u32 id, int khz)
{
- struct nva3_pm_state *state;
- int dummy, ret;
+ struct nva3_pm_state *pll;
+ struct pll_lims limits;
+ int N, M, P, diff;
+ int ret, off;
+
+ ret = get_pll_limits(dev, id, &limits);
+ if (ret < 0)
+ return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+
+ off = nva3_pm_pll_offset(id);
+ if (id < 0)
+ return ERR_PTR(-EINVAL);
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
return ERR_PTR(-ENOMEM);
+ pll->type = id;
+ pll->src0 = 0x004120 + (off * 4);
+ pll->src1 = 0x004160 + (off * 4);
+ pll->ctrl = limits.reg + 0;
+ pll->coef = limits.reg + 4;
- ret = get_pll_limits(dev, id, &state->pll);
- if (ret < 0) {
- kfree(state);
- return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+ /* If target clock is within [-2, 3) MHz of a divisor, we'll
+ * use that instead of calculating MNP values
+ */
+ pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16);
+ if (pll->new_div) {
+ diff = khz - ((limits.refclk * 2) / pll->new_div);
+ if (diff < -2000 || diff >= 3000)
+ pll->new_div = 0;
}
- ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
- &state->M, &state->P);
- if (ret < 0) {
- kfree(state);
- return ERR_PTR(ret);
+ if (!pll->new_div) {
+ ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ pll->new_pnm = (P << 16) | (N << 8) | M;
+ pll->new_div = 2 - 1;
+ } else {
+ pll->new_pnm = 0;
+ pll->new_div--;
}
- return state;
+ if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
+ pll->old_pnm = nv_rd32(dev, pll->coef);
+ return pll;
}
void
nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
{
- struct nva3_pm_state *state = pre_state;
- u32 reg = state->pll.reg;
+ struct nva3_pm_state *pll = pre_state;
+ u32 ctrl = 0;
+
+ /* For the memory clock, NVIDIA will build a "script" describing
+ * the reclocking process and ask PDAEMON to execute it.
+ */
+ if (pll->type == PLL_MEMORY) {
+ nv_wr32(dev, 0x100210, 0);
+ nv_wr32(dev, 0x1002dc, 1);
+ nv_wr32(dev, 0x004018, 0x00001000);
+ ctrl = 0x18000100;
+ }
+
+ if (pll->old_pnm || !pll->new_pnm) {
+ nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
+ (pll->new_div << 18));
+ nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+ nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+ }
+
+ if (pll->new_pnm) {
+ nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
+ nv_wr32(dev, pll->coef, pll->new_pnm);
+ nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+ nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
+ nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
+ nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
+ nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
+ nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
+ if (pll->type == PLL_MEMORY)
+ nv_wr32(dev, 0x4018, 0x10005000);
+ } else {
+ nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+ nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
+ nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
+ if (pll->type == PLL_MEMORY)
+ nv_wr32(dev, 0x4018, 0x1000d000);
+ }
+
+ if (pll->type == PLL_MEMORY) {
+ nv_wr32(dev, 0x1002dc, 0);
+ nv_wr32(dev, 0x100210, 0x80000000);
+ }
- nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
- kfree(state);
+ kfree(pll);
}
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.c b/drivers/gpu/drm/nouveau/nvc0_copy.c
new file mode 100644
index 000000000000..208fa7ab3f42
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_copy.c
@@ -0,0 +1,243 @@
+/*
+ * 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
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nvc0_copy.fuc.h"
+
+struct nvc0_copy_engine {
+ struct nouveau_exec_engine base;
+ u32 irq;
+ u32 pmc;
+ u32 fuc;
+ u32 ctx;
+};
+
+static int
+nvc0_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
+ NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER |
+ NVOBJ_FLAG_ZERO_ALLOC, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->vinst));
+ nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->vinst));
+ dev_priv->engine.instmem.flush(dev);
+
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static int
+nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ return 0;
+}
+
+static void
+nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ u32 inst;
+
+ inst = (chan->ramin->vinst >> 12);
+ inst |= 0x40000000;
+
+ /* disable fifo access */
+ nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000);
+ /* mark channel as unloaded if it's currently active */
+ if (nv_rd32(dev, pcopy->fuc + 0x050) == inst)
+ nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000);
+ /* mark next channel as invalid if it's about to be loaded */
+ if (nv_rd32(dev, pcopy->fuc + 0x054) == inst)
+ nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+ /* restore fifo access */
+ nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003);
+
+ nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000);
+ nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000);
+ nouveau_gpuobj_ref(NULL, &ctx);
+
+ chan->engctx[engine] = ctx;
+}
+
+static int
+nvc0_copy_init(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+ int i;
+
+ nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000);
+ nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc);
+ nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+
+ nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000);
+ for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
+ nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]);
+
+ nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000);
+ for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(dev, pcopy->fuc + 0x188, i >> 6);
+ nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]);
+ }
+
+ nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0);
+ nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000);
+ nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */
+ nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */
+ return 0;
+}
+
+static int
+nvc0_copy_fini(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+ nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
+
+ /* trigger fuc context unload */
+ nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000);
+ nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+ nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008);
+ nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000);
+
+ nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+ return 0;
+}
+
+static struct nouveau_enum nvc0_copy_isr_error_name[] = {
+ { 0x0001, "ILLEGAL_MTHD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "INVALID_BITFIELD" },
+ {}
+};
+
+static void
+nvc0_copy_isr(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+ u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c);
+ u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16);
+ u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12;
+ u32 chid = nvc0_graph_isr_chid(dev, inst);
+ u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff;
+ u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_rd32(dev, pcopy->fuc + 0x044);
+
+ if (stat & 0x00000040) {
+ NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+ nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
+ printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, mthd, data);
+ nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+ nv_wr32(dev, pcopy->fuc + 0x004, stat);
+ }
+}
+
+static void
+nvc0_copy_isr_0(struct drm_device *dev)
+{
+ nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0);
+}
+
+static void
+nvc0_copy_isr_1(struct drm_device *dev)
+{
+ nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1);
+}
+
+static void
+nvc0_copy_destroy(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, pcopy->irq);
+
+ if (engine == NVOBJ_ENGINE_COPY0)
+ NVOBJ_ENGINE_DEL(dev, COPY0);
+ else
+ NVOBJ_ENGINE_DEL(dev, COPY1);
+ kfree(pcopy);
+}
+
+int
+nvc0_copy_create(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy;
+
+ pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+ if (!pcopy)
+ return -ENOMEM;
+
+ pcopy->base.destroy = nvc0_copy_destroy;
+ pcopy->base.init = nvc0_copy_init;
+ pcopy->base.fini = nvc0_copy_fini;
+ pcopy->base.context_new = nvc0_copy_context_new;
+ pcopy->base.context_del = nvc0_copy_context_del;
+ pcopy->base.object_new = nvc0_copy_object_new;
+
+ if (engine == 0) {
+ pcopy->irq = 5;
+ pcopy->pmc = 0x00000040;
+ pcopy->fuc = 0x104000;
+ pcopy->ctx = 0x0230;
+ nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0);
+ NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+ NVOBJ_CLASS(dev, 0x90b5, COPY0);
+ } else {
+ pcopy->irq = 6;
+ pcopy->pmc = 0x00000080;
+ pcopy->fuc = 0x105000;
+ pcopy->ctx = 0x0240;
+ nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1);
+ NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base);
+ NVOBJ_CLASS(dev, 0x90b8, COPY1);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
new file mode 100644
index 000000000000..419903880e9d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
@@ -0,0 +1,527 @@
+uint32_t nvc0_pcopy_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,
+ 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,
+ 0x00010000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010040,
+ 0x0001019f,
+ 0x00000000,
+ 0x00010050,
+ 0x000101a1,
+ 0x00000000,
+ 0x00070080,
+ 0x0000001c,
+ 0xfffff000,
+ 0x00000020,
+ 0xfff80000,
+ 0x00000024,
+ 0xffffe000,
+ 0x00000028,
+ 0xfffff800,
+ 0x0000002c,
+ 0xfffff000,
+ 0x00000030,
+ 0xfff80000,
+ 0x00000034,
+ 0xffffe000,
+ 0x00070088,
+ 0x00000048,
+ 0xfffff000,
+ 0x0000004c,
+ 0xfff80000,
+ 0x00000050,
+ 0xffffe000,
+ 0x00000054,
+ 0xfffff800,
+ 0x00000058,
+ 0xfffff000,
+ 0x0000005c,
+ 0xfff80000,
+ 0x00000060,
+ 0xffffe000,
+ 0x000200c0,
+ 0x000104b8,
+ 0x00000000,
+ 0x00010541,
+ 0x00000000,
+ 0x000e00c3,
+ 0x00000010,
+ 0xffffff00,
+ 0x00000014,
+ 0x0000000f,
+ 0x0000003c,
+ 0xffffff00,
+ 0x00000040,
+ 0x0000000f,
+ 0x00000018,
+ 0xfff80000,
+ 0x00000044,
+ 0xfff80000,
+ 0x00000074,
+ 0xffff0000,
+ 0x00000078,
+ 0xffffe000,
+ 0x00000068,
+ 0xfccc0000,
+ 0x0000006c,
+ 0x00000000,
+ 0x00000070,
+ 0x00000000,
+ 0x00000004,
+ 0xffffff00,
+ 0x00000008,
+ 0x00000000,
+ 0x0000000c,
+ 0x00000000,
+ 0x00000800,
+};
+
+uint32_t nvc0_pcopy_code[] = {
+ 0x04fe04bd,
+ 0x3517f000,
+ 0xf10010fe,
+ 0xf1040017,
+ 0xf0fff327,
+ 0x22d00023,
+ 0x0c25f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x27f01200,
+ 0x0012d003,
+ 0xf40031f4,
+ 0x0ef40028,
+ 0x8001cffd,
+ 0xf40812c4,
+ 0x21f4060b,
+ 0x0412c4ca,
+ 0xf5070bf4,
+ 0xc4010221,
+ 0x01d00c11,
+ 0xf101f840,
+ 0xfe770047,
+ 0x47f1004b,
+ 0x44cf2100,
+ 0x0144f000,
+ 0xb60444b6,
+ 0xf7f13040,
+ 0xf4b6061c,
+ 0x1457f106,
+ 0x00f5d101,
+ 0xb6043594,
+ 0x57fe0250,
+ 0x0145fe00,
+ 0x010052b7,
+ 0x00ff67f1,
+ 0x56fd60bd,
+ 0x0253f004,
+ 0xf80545fa,
+ 0x0053f003,
+ 0xd100e7f0,
+ 0x549800fe,
+ 0x0845b600,
+ 0xb6015698,
+ 0x46fd1864,
+ 0x0047fe05,
+ 0xf00204b9,
+ 0x01f40643,
+ 0x0604fa09,
+ 0xfa060ef4,
+ 0x03f80504,
+ 0x27f100f8,
+ 0x23cf1400,
+ 0x1e3fc800,
+ 0xf4170bf4,
+ 0x21f40132,
+ 0x1e3af053,
+ 0xf00023d0,
+ 0x24d00147,
+ 0xcf00f880,
+ 0x3dc84023,
+ 0x090bf41e,
+ 0xf40131f4,
+ 0x37f05321,
+ 0x8023d002,
+ 0x37f100f8,
+ 0x32cf1900,
+ 0x0033cf40,
+ 0x07ff24e4,
+ 0xf11024b6,
+ 0xbd010057,
+ 0x5874bd64,
+ 0x57580056,
+ 0x0450b601,
+ 0xf40446b8,
+ 0x76bb4d08,
+ 0x0447b800,
+ 0xbb0f08f4,
+ 0x74b60276,
+ 0x0057bb03,
+ 0xbbdf0ef4,
+ 0x44b60246,
+ 0x0045bb03,
+ 0xfd014598,
+ 0x54b00453,
+ 0x201bf400,
+ 0x58004558,
+ 0x64b00146,
+ 0x091bf400,
+ 0xf4005380,
+ 0x32f4300e,
+ 0xf455f901,
+ 0x0ef40c01,
+ 0x0225f025,
+ 0xf10125f0,
+ 0xd0100047,
+ 0x43d00042,
+ 0x4027f040,
+ 0xcf0002d0,
+ 0x24f08002,
+ 0x0024b040,
+ 0xf1f71bf4,
+ 0xf01d0027,
+ 0x23d00137,
+ 0xf800f800,
+ 0x0027f100,
+ 0xf034bd22,
+ 0x23d00233,
+ 0xf400f800,
+ 0x01b0f030,
+ 0x0101b000,
+ 0xb00201b0,
+ 0x04980301,
+ 0x3045c71a,
+ 0xc70150b6,
+ 0x60b63446,
+ 0x3847c701,
+ 0xf40170b6,
+ 0x84bd0232,
+ 0x4ac494bd,
+ 0x0445b60f,
+ 0xa430b4bd,
+ 0x0f18f404,
+ 0xbbc0a5ff,
+ 0x31f400cb,
+ 0x220ef402,
+ 0xf00c1bf4,
+ 0xcbbb10c7,
+ 0x160ef400,
+ 0xf406a430,
+ 0xc7f00c18,
+ 0x00cbbb14,
+ 0xf1070ef4,
+ 0x380080c7,
+ 0x80b601c8,
+ 0x01b0b601,
+ 0xf404b5b8,
+ 0x90b6c308,
+ 0x0497b801,
+ 0xfdb208f4,
+ 0x06800065,
+ 0x1d08980e,
+ 0xf40068fd,
+ 0x64bd0502,
+ 0x800075fd,
+ 0x78fd1907,
+ 0x1057f100,
+ 0x0654b608,
+ 0xd00056d0,
+ 0x50b74057,
+ 0x06980800,
+ 0x0162b619,
+ 0x980864b6,
+ 0x72b60e07,
+ 0x0567fd01,
+ 0xb70056d0,
+ 0xb4010050,
+ 0x56d00060,
+ 0x0160b400,
+ 0xb44056d0,
+ 0x56d00260,
+ 0x0360b480,
+ 0xb7c056d0,
+ 0x98040050,
+ 0x56d01b06,
+ 0x1c069800,
+ 0xf44056d0,
+ 0x00f81030,
+ 0xc7075798,
+ 0x78c76879,
+ 0x0380b664,
+ 0xb06077c7,
+ 0x1bf40e76,
+ 0x0477f009,
+ 0xf00f0ef4,
+ 0x70b6027c,
+ 0x0947fd11,
+ 0x980677f0,
+ 0x5b980c5a,
+ 0x00abfd0e,
+ 0xbb01b7f0,
+ 0xb2b604b7,
+ 0xc4abff01,
+ 0x9805a7bb,
+ 0xe7f00d5d,
+ 0x04e8bb01,
+ 0xff01e2b6,
+ 0xd8bbb4de,
+ 0x01e0b605,
+ 0xbb0cef94,
+ 0xfefd02eb,
+ 0x026cf005,
+ 0x020860b7,
+ 0xd00864b6,
+ 0xb7bb006f,
+ 0x00cbbb04,
+ 0x98085f98,
+ 0xfbfd0e5b,
+ 0x01b7f000,
+ 0xb604b7bb,
+ 0xfbbb01b2,
+ 0x05f7bb00,
+ 0x5f98f0f9,
+ 0x01b7f009,
+ 0xb604b8bb,
+ 0xfbbb01b2,
+ 0x05f8bb00,
+ 0x78bbf0f9,
+ 0x0282b600,
+ 0xbb01b7f0,
+ 0xb9bb04b8,
+ 0x0b589804,
+ 0xbb01e7f0,
+ 0xe2b604e9,
+ 0xf48eff01,
+ 0xbb04f7bb,
+ 0x79bb00cf,
+ 0x0589bb00,
+ 0x90fcf0fc,
+ 0xbb00d9fd,
+ 0x89fd00ad,
+ 0x008ffd00,
+ 0xbb00a8bb,
+ 0x92b604a7,
+ 0x0497bb01,
+ 0x988069d0,
+ 0x58980557,
+ 0x00acbb04,
+ 0xb6007abb,
+ 0x84b60081,
+ 0x058bfd10,
+ 0x060062b7,
+ 0xb70067d0,
+ 0xd0040060,
+ 0x00f80068,
+ 0xb7026cf0,
+ 0xb6020260,
+ 0x57980864,
+ 0x0067d005,
+ 0x040060b7,
+ 0xb6045798,
+ 0x67d01074,
+ 0x0060b700,
+ 0x06579804,
+ 0xf80067d0,
+ 0xf900f900,
+ 0x0007f110,
+ 0x0604b608,
+ 0xf00001cf,
+ 0x1bf40114,
+ 0xfc10fcfa,
+ 0xc800f800,
+ 0x1bf40d34,
+ 0xd121f570,
+ 0x0c47f103,
+ 0x0644b608,
+ 0xb6020598,
+ 0x45d00450,
+ 0x4040d000,
+ 0xd00c57f0,
+ 0x40b78045,
+ 0x05980400,
+ 0x1054b601,
+ 0xb70045d0,
+ 0xf1050040,
+ 0xf00b0057,
+ 0x45d00153,
+ 0x4057f100,
+ 0x0154b640,
+ 0x808053f1,
+ 0xf14045d0,
+ 0xf1111057,
+ 0xd0131253,
+ 0x57f18045,
+ 0x53f11514,
+ 0x45d01716,
+ 0x0157f1c0,
+ 0x0153f026,
+ 0x080047f1,
+ 0xd00644b6,
+ 0x21f50045,
+ 0x47f103d1,
+ 0x44b6080c,
+ 0x02059806,
+ 0xd00045d0,
+ 0x57f04040,
+ 0x8045d004,
+ 0x040040b7,
+ 0xb6010598,
+ 0x45d01054,
+ 0x0040b700,
+ 0x0057f105,
+ 0x0045d003,
+ 0x111057f1,
+ 0x131253f1,
+ 0x984045d0,
+ 0x40b70305,
+ 0x45d00500,
+ 0x0157f100,
+ 0x0153f026,
+ 0x080047f1,
+ 0xd00644b6,
+ 0x00f80045,
+ 0x03d121f5,
+ 0xf4003fc8,
+ 0x21f50e0b,
+ 0x47f101af,
+ 0x0ef40200,
+ 0x1067f11e,
+ 0x0664b608,
+ 0x800177f0,
+ 0x07800e07,
+ 0x1d079819,
+ 0xd00067d0,
+ 0x44bd4067,
+ 0xbd0232f4,
+ 0x043fc854,
+ 0xf50a0bf4,
+ 0xf403a821,
+ 0x21f50a0e,
+ 0x49f0029c,
+ 0x0231f407,
+ 0xc82c57f0,
+ 0x0bf4083f,
+ 0xa821f50a,
+ 0x0a0ef403,
+ 0x029c21f5,
+ 0xf10849f0,
+ 0xb6080057,
+ 0x06980654,
+ 0x4056d01e,
+ 0xf14167f0,
+ 0xfd440063,
+ 0x54d00546,
+ 0x0c3fc800,
+ 0xf5070bf4,
+ 0xf803eb21,
+ 0x0027f100,
+ 0xf034bd22,
+ 0x23d00133,
+ 0x0000f800,
+ 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,
+};
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index 2886f2726a9e..fb4f5943e01b 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -37,7 +37,7 @@ struct nvc0_fifo_priv {
};
struct nvc0_fifo_chan {
- struct nouveau_bo *user;
+ struct nouveau_gpuobj *user;
struct nouveau_gpuobj *ramfc;
};
@@ -106,7 +106,7 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nvc0_fifo_priv *priv = pfifo->priv;
struct nvc0_fifo_chan *fifoch;
- u64 ib_virt, user_vinst;
+ u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
int ret;
chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
@@ -115,28 +115,13 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
fifoch = chan->fifo_priv;
/* allocate vram for control regs, map into polling area */
- ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM,
- 0, 0, &fifoch->user);
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user);
if (ret)
goto error;
- ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM);
- if (ret) {
- nouveau_bo_ref(NULL, &fifoch->user);
- goto error;
- }
-
- user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT;
-
- ret = nouveau_bo_map(fifoch->user);
- if (ret) {
- nouveau_bo_unpin(fifoch->user);
- nouveau_bo_ref(NULL, &fifoch->user);
- goto error;
- }
-
nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
- fifoch->user->bo.mem.mm_node);
+ *(struct nouveau_mem **)fifoch->user->node);
chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
priv->user_vma.offset + (chan->id * 0x1000),
@@ -146,20 +131,6 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
goto error;
}
- ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-
- /* zero channel regs */
- nouveau_bo_wr32(fifoch->user, 0x0040/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0044/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0048/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x004c/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0050/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0058/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x005c/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0060/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0088/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x008c/4, 0);
-
/* ramfc */
ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
chan->ramin->vinst, 0x100,
@@ -167,8 +138,8 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
if (ret)
goto error;
- nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst));
- nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst));
+ nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst));
+ nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst));
nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
@@ -223,11 +194,7 @@ nvc0_fifo_destroy_context(struct nouveau_channel *chan)
return;
nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
- if (fifoch->user) {
- nouveau_bo_unmap(fifoch->user);
- nouveau_bo_unpin(fifoch->user);
- nouveau_bo_ref(NULL, &fifoch->user);
- }
+ nouveau_gpuobj_ref(NULL, &fifoch->user);
kfree(fifoch);
}
@@ -240,6 +207,21 @@ nvc0_fifo_load_context(struct nouveau_channel *chan)
int
nvc0_fifo_unload_context(struct drm_device *dev)
{
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ if (!(nv_rd32(dev, 0x003004 + (i * 4)) & 1))
+ continue;
+
+ nv_mask(dev, 0x003004 + (i * 4), 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x002634, i);
+ if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+ NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+ i, nv_rd32(dev, 0x002634));
+ return -EBUSY;
+ }
+ }
+
return 0;
}
@@ -309,6 +291,7 @@ nvc0_fifo_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_channel *chan;
struct nvc0_fifo_priv *priv;
int ret, i;
@@ -351,23 +334,74 @@ nvc0_fifo_init(struct drm_device *dev)
nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xbfffffff);
+
+ /* restore PFIFO context table */
+ for (i = 0; i < 128; i++) {
+ chan = dev_priv->channels.ptr[i];
+ if (!chan || !chan->fifo_priv)
+ continue;
+
+ nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
+ (chan->ramin->vinst >> 12));
+ nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001);
+ }
+ nvc0_fifo_playlist_update(dev);
+
return 0;
}
struct nouveau_enum nvc0_fifo_fault_unit[] = {
- { 0, "PGRAPH" },
- { 3, "PEEPHOLE" },
- { 4, "BAR1" },
- { 5, "BAR3" },
- { 7, "PFIFO" },
+ { 0x00, "PGRAPH" },
+ { 0x03, "PEEPHOLE" },
+ { 0x04, "BAR1" },
+ { 0x05, "BAR3" },
+ { 0x07, "PFIFO" },
+ { 0x10, "PBSP" },
+ { 0x11, "PPPP" },
+ { 0x13, "PCOUNTER" },
+ { 0x14, "PVP" },
+ { 0x15, "PCOPY0" },
+ { 0x16, "PCOPY1" },
+ { 0x17, "PDAEMON" },
{}
};
struct nouveau_enum nvc0_fifo_fault_reason[] = {
- { 0, "PT_NOT_PRESENT" },
- { 1, "PT_TOO_SHORT" },
- { 2, "PAGE_NOT_PRESENT" },
- { 3, "VM_LIMIT_EXCEEDED" },
+ { 0x00, "PT_NOT_PRESENT" },
+ { 0x01, "PT_TOO_SHORT" },
+ { 0x02, "PAGE_NOT_PRESENT" },
+ { 0x03, "VM_LIMIT_EXCEEDED" },
+ { 0x04, "NO_CHANNEL" },
+ { 0x05, "PAGE_SYSTEM_ONLY" },
+ { 0x06, "PAGE_READ_ONLY" },
+ { 0x0a, "COMPRESSED_SYSRAM" },
+ { 0x0c, "INVALID_STORAGE_TYPE" },
+ {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
+ { 0x01, "PCOPY0" },
+ { 0x02, "PCOPY1" },
+ { 0x04, "DISPATCH" },
+ { 0x05, "CTXCTL" },
+ { 0x06, "PFIFO" },
+ { 0x07, "BAR_READ" },
+ { 0x08, "BAR_WRITE" },
+ { 0x0b, "PVP" },
+ { 0x0c, "PPPP" },
+ { 0x0d, "PBSP" },
+ { 0x11, "PCOUNTER" },
+ { 0x12, "PDAEMON" },
+ { 0x14, "CCACHE" },
+ { 0x15, "CCACHE_POST" },
+ {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
+ { 0x01, "TEX" },
+ { 0x0c, "ESETUP" },
+ { 0x0e, "CTXCTL" },
+ { 0x0f, "PROP" },
{}
};
@@ -385,12 +419,20 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+ u32 client = (stat & 0x00001f00) >> 8;
NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
(stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
printk("] from ");
nouveau_enum_print(nvc0_fifo_fault_unit, unit);
+ if (stat & 0x00000040) {
+ printk("/");
+ nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
+ } else {
+ printk("/GPC%d/", (stat & 0x1f000000) >> 24);
+ nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
+ }
printk(" on channel 0x%010llx\n", (u64)inst << 12);
}
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 3de9b721d8db..ca6db204d644 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -30,27 +30,40 @@
#include "nouveau_mm.h"
#include "nvc0_graph.h"
-static void nvc0_graph_isr(struct drm_device *);
-static void nvc0_runk140_isr(struct drm_device *);
-static int nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
-
-void
-nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+static int
+nvc0_graph_load_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+
+ nv_wr32(dev, 0x409840, 0x00000030);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
+ nv_wr32(dev, 0x409504, 0x00000003);
+ if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
+ NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
+
+ return 0;
}
-struct nouveau_channel *
-nvc0_graph_channel(struct drm_device *dev)
+static int
+nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
{
- return NULL;
+ nv_wr32(dev, 0x409840, 0x00000003);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
+ nv_wr32(dev, 0x409504, 0x00000009);
+ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
+ return -EBUSY;
+ }
+
+ return 0;
}
static int
nvc0_graph_construct_context(struct nouveau_channel *chan)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
int ret, i;
u32 *ctx;
@@ -89,9 +102,8 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
static int
nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
int i = 0, gpc, tp, ret;
u32 magic;
@@ -158,29 +170,27 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
return 0;
}
-int
-nvc0_graph_create_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv = pgraph->priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, engine);
struct nvc0_graph_chan *grch;
- struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *grctx;
int ret, i;
- chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL);
- if (!chan->pgraph_ctx)
+ grch = kzalloc(sizeof(*grch), GFP_KERNEL);
+ if (!grch)
return -ENOMEM;
- grch = chan->pgraph_ctx;
+ chan->engctx[NVOBJ_ENGINE_GR] = grch;
ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256,
NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC,
&grch->grctx);
if (ret)
goto error;
- chan->ramin_grctx = grch->grctx;
grctx = grch->grctx;
ret = nvc0_graph_create_context_mmio_list(chan);
@@ -200,104 +210,49 @@ nvc0_graph_create_context(struct nouveau_channel *chan)
for (i = 0; i < priv->grctx_size; i += 4)
nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
- nv_wo32(grctx, 0xf4, 0);
- nv_wo32(grctx, 0xf8, 0);
- nv_wo32(grctx, 0x10, grch->mmio_nr);
- nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
- nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
- nv_wo32(grctx, 0x1c, 1);
- nv_wo32(grctx, 0x20, 0);
- nv_wo32(grctx, 0x28, 0);
- nv_wo32(grctx, 0x2c, 0);
+ nv_wo32(grctx, 0xf4, 0);
+ nv_wo32(grctx, 0xf8, 0);
+ nv_wo32(grctx, 0x10, grch->mmio_nr);
+ nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
+ nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
+ nv_wo32(grctx, 0x1c, 1);
+ nv_wo32(grctx, 0x20, 0);
+ nv_wo32(grctx, 0x28, 0);
+ nv_wo32(grctx, 0x2c, 0);
pinstmem->flush(dev);
return 0;
error:
- pgraph->destroy_context(chan);
+ priv->base.context_del(chan, engine);
return ret;
}
-void
-nvc0_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nvc0_graph_context_del(struct nouveau_channel *chan, int engine)
{
- struct nvc0_graph_chan *grch;
-
- grch = chan->pgraph_ctx;
- chan->pgraph_ctx = NULL;
- if (!grch)
- return;
+ struct nvc0_graph_chan *grch = chan->engctx[engine];
nouveau_gpuobj_ref(NULL, &grch->mmio);
nouveau_gpuobj_ref(NULL, &grch->unk418810);
nouveau_gpuobj_ref(NULL, &grch->unk40800c);
nouveau_gpuobj_ref(NULL, &grch->unk408004);
nouveau_gpuobj_ref(NULL, &grch->grctx);
- chan->ramin_grctx = NULL;
+ chan->engctx[engine] = NULL;
}
-int
-nvc0_graph_load_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
{
- struct drm_device *dev = chan->dev;
-
- nv_wr32(dev, 0x409840, 0x00000030);
- nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
- nv_wr32(dev, 0x409504, 0x00000003);
- if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
- NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
-
return 0;
}
static int
-nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
+nvc0_graph_fini(struct drm_device *dev, int engine)
{
- nv_wr32(dev, 0x409840, 0x00000003);
- nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
- nv_wr32(dev, 0x409504, 0x00000009);
- if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
- return -EBUSY;
- }
-
return 0;
}
-int
-nvc0_graph_unload_context(struct drm_device *dev)
-{
- u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
- return nvc0_graph_unload_context_to(dev, inst);
-}
-
-static void
-nvc0_graph_destroy(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv;
-
- priv = pgraph->priv;
- if (!priv)
- return;
-
- nouveau_irq_unregister(dev, 12);
- nouveau_irq_unregister(dev, 25);
-
- nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
- nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
- if (priv->grctx_vals)
- kfree(priv->grctx_vals);
- kfree(priv);
-}
-
-void
-nvc0_graph_takedown(struct drm_device *dev)
-{
- nvc0_graph_destroy(dev);
-}
-
static int
nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data)
@@ -306,119 +261,10 @@ nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
return 0;
}
-static int
-nvc0_graph_create(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv;
- int ret, gpc, i;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- pgraph->priv = priv;
-
- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
- if (ret)
- goto error;
-
- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
- if (ret)
- goto error;
-
- for (i = 0; i < 0x1000; i += 4) {
- nv_wo32(priv->unk4188b4, i, 0x00000010);
- nv_wo32(priv->unk4188b8, i, 0x00000010);
- }
-
- priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f;
- priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
- priv->tp_total += priv->tp_nr[gpc];
- }
-
- /*XXX: these need figuring out... */
- switch (dev_priv->chipset) {
- case 0xc0:
- if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
- priv->magic_not_rop_nr = 0x07;
- /* filled values up to tp_total, the rest 0 */
- priv->magicgpc980[0] = 0x22111000;
- priv->magicgpc980[1] = 0x00000233;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x000ba2e9;
- } else
- if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
- priv->magic_not_rop_nr = 0x05;
- priv->magicgpc980[0] = 0x11110000;
- priv->magicgpc980[1] = 0x00233222;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00092493;
- } else
- if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
- priv->magic_not_rop_nr = 0x06;
- priv->magicgpc980[0] = 0x11110000;
- priv->magicgpc980[1] = 0x03332222;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00088889;
- }
- break;
- case 0xc3: /* 450, 4/0/0/0, 2 */
- priv->magic_not_rop_nr = 0x03;
- priv->magicgpc980[0] = 0x00003210;
- priv->magicgpc980[1] = 0x00000000;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00200000;
- break;
- case 0xc4: /* 460, 3/4/0/0, 4 */
- priv->magic_not_rop_nr = 0x01;
- priv->magicgpc980[0] = 0x02321100;
- priv->magicgpc980[1] = 0x00000000;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00124925;
- break;
- }
-
- if (!priv->magic_not_rop_nr) {
- NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
- priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
- priv->tp_nr[3], priv->rop_nr);
- /* use 0xc3's values... */
- priv->magic_not_rop_nr = 0x03;
- priv->magicgpc980[0] = 0x00003210;
- priv->magicgpc980[1] = 0x00000000;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00200000;
- }
-
- nouveau_irq_register(dev, 12, nvc0_graph_isr);
- nouveau_irq_register(dev, 25, nvc0_runk140_isr);
- NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
- NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
- NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
- NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
- NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
- return 0;
-
-error:
- nvc0_graph_destroy(dev);
- return ret;
-}
-
static void
nvc0_graph_init_obj418880(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv = pgraph->priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int i;
nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
@@ -449,35 +295,42 @@ nvc0_graph_init_regs(struct drm_device *dev)
static void
nvc0_graph_init_gpc_0(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- int gpc;
-
- // TP ROP UNKVAL(magic_not_rop_nr)
- // 450: 4/0/0/0 2 3
- // 460: 3/4/0/0 4 1
- // 465: 3/4/4/0 4 7
- // 470: 3/3/4/4 5 5
- // 480: 3/4/4/4 6 6
-
- // magicgpc918
- // 450: 00200000 00000000001000000000000000000000
- // 460: 00124925 00000000000100100100100100100101
- // 465: 000ba2e9 00000000000010111010001011101001
- // 470: 00092493 00000000000010010010010010010011
- // 480: 00088889 00000000000010001000100010001001
-
- /* filled values up to tp_total, remainder 0 */
- // 450: 00003210 00000000 00000000 00000000
- // 460: 02321100 00000000 00000000 00000000
- // 465: 22111000 00000233 00000000 00000000
- // 470: 11110000 00233222 00000000 00000000
- // 480: 11110000 03332222 00000000 00000000
-
- nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]);
- nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]);
- nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]);
- nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]);
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ u32 data[TP_MAX / 8];
+ u8 tpnr[GPC_MAX];
+ int i, gpc, tpc;
+
+ /*
+ * TP ROP UNKVAL(magic_not_rop_nr)
+ * 450: 4/0/0/0 2 3
+ * 460: 3/4/0/0 4 1
+ * 465: 3/4/4/0 4 7
+ * 470: 3/3/4/4 5 5
+ * 480: 3/4/4/4 6 6
+ *
+ * magicgpc918
+ * 450: 00200000 00000000001000000000000000000000
+ * 460: 00124925 00000000000100100100100100100101
+ * 465: 000ba2e9 00000000000010111010001011101001
+ * 470: 00092493 00000000000010010010010010010011
+ * 480: 00088889 00000000000010001000100010001001
+ */
+
+ memset(data, 0x00, sizeof(data));
+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+ for (i = 0, gpc = -1; i < priv->tp_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpnr[gpc]);
+ tpc = priv->tp_nr[gpc] - tpnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
@@ -509,8 +362,7 @@ nvc0_graph_init_units(struct drm_device *dev)
static void
nvc0_graph_init_gpc_1(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int gpc, tp;
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
@@ -535,8 +387,7 @@ nvc0_graph_init_gpc_1(struct drm_device *dev)
static void
nvc0_graph_init_rop(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int rop;
for (rop = 0; rop < priv->rop_nr; rop++) {
@@ -547,62 +398,36 @@ nvc0_graph_init_rop(struct drm_device *dev)
}
}
-static int
-nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base,
- const char *code_fw, const char *data_fw)
+static void
+nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
+ struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
{
- const struct firmware *fw;
- char name[32];
- int ret, i;
-
- snprintf(name, sizeof(name), "nouveau/%s", data_fw);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "failed to load %s\n", data_fw);
- return ret;
- }
+ int i;
nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
- for (i = 0; i < fw->size / 4; i++)
- nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]);
- release_firmware(fw);
-
- snprintf(name, sizeof(name), "nouveau/%s", code_fw);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "failed to load %s\n", code_fw);
- return ret;
- }
+ for (i = 0; i < data->size / 4; i++)
+ nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
- for (i = 0; i < fw->size / 4; i++) {
+ for (i = 0; i < code->size / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(dev, fuc_base + 0x0188, i >> 6);
- nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]);
+ nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
}
- release_firmware(fw);
-
- return 0;
}
static int
nvc0_graph_init_ctxctl(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
u32 r000260;
- int ret;
/* load fuc microcode */
r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
- ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d");
- if (ret == 0)
- ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad");
+ nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
+ nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
nv_wr32(dev, 0x000260, r000260);
- if (ret)
- return ret;
-
/* start both of them running */
nv_wr32(dev, 0x409840, 0xffffffff);
nv_wr32(dev, 0x41a10c, 0x00000000);
@@ -644,41 +469,19 @@ nvc0_graph_init_ctxctl(struct drm_device *dev)
return 0;
}
-int
-nvc0_graph_init(struct drm_device *dev)
+static int
+nvc0_graph_init(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int ret;
- dev_priv->engine.graph.accel_blocked = true;
-
- switch (dev_priv->chipset) {
- case 0xc0:
- case 0xc3:
- case 0xc4:
- break;
- default:
- NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
- if (nouveau_noaccel != 0)
- return 0;
- break;
- }
-
nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
- if (!pgraph->priv) {
- ret = nvc0_graph_create(dev);
- if (ret)
- return ret;
- }
-
nvc0_graph_init_obj418880(dev);
nvc0_graph_init_regs(dev);
- //nvc0_graph_init_unitplemented_magics(dev);
+ /*nvc0_graph_init_unitplemented_magics(dev);*/
nvc0_graph_init_gpc_0(dev);
- //nvc0_graph_init_unitplemented_c242(dev);
+ /*nvc0_graph_init_unitplemented_c242(dev);*/
nv_wr32(dev, 0x400500, 0x00010001);
nv_wr32(dev, 0x400100, 0xffffffff);
@@ -697,12 +500,13 @@ nvc0_graph_init(struct drm_device *dev)
nv_wr32(dev, 0x400054, 0x34ce3464);
ret = nvc0_graph_init_ctxctl(dev);
- if (ret == 0)
- dev_priv->engine.graph.accel_blocked = false;
+ if (ret)
+ return ret;
+
return 0;
}
-static int
+int
nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -806,3 +610,187 @@ nvc0_runk140_isr(struct drm_device *dev)
units &= ~(1 << unit);
}
}
+
+static int
+nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
+ struct nvc0_graph_fuc *fuc)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ const struct firmware *fw;
+ char f[32];
+ int ret;
+
+ snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
+ ret = request_firmware(&fw, f, &dev->pdev->dev);
+ if (ret) {
+ snprintf(f, sizeof(f), "nouveau/%s", fwname);
+ ret = request_firmware(&fw, f, &dev->pdev->dev);
+ if (ret) {
+ NV_ERROR(dev, "failed to load %s\n", fwname);
+ return ret;
+ }
+ }
+
+ fuc->size = fw->size;
+ fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+ release_firmware(fw);
+ return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+static void
+nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
+{
+ if (fuc->data) {
+ kfree(fuc->data);
+ fuc->data = NULL;
+ }
+}
+
+static void
+nvc0_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nvc0_graph_priv *priv = nv_engine(dev, engine);
+
+ nvc0_graph_destroy_fw(&priv->fuc409c);
+ nvc0_graph_destroy_fw(&priv->fuc409d);
+ nvc0_graph_destroy_fw(&priv->fuc41ac);
+ nvc0_graph_destroy_fw(&priv->fuc41ad);
+
+ nouveau_irq_unregister(dev, 12);
+ nouveau_irq_unregister(dev, 25);
+
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+ if (priv->grctx_vals)
+ kfree(priv->grctx_vals);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(priv);
+}
+
+int
+nvc0_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_graph_priv *priv;
+ int ret, gpc, i;
+
+ switch (dev_priv->chipset) {
+ case 0xc0:
+ case 0xc3:
+ case 0xc4:
+ break;
+ default:
+ NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
+ return 0;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.destroy = nvc0_graph_destroy;
+ priv->base.init = nvc0_graph_init;
+ priv->base.fini = nvc0_graph_fini;
+ priv->base.context_new = nvc0_graph_context_new;
+ priv->base.context_del = nvc0_graph_context_del;
+ priv->base.object_new = nvc0_graph_object_new;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
+ nouveau_irq_register(dev, 12, nvc0_graph_isr);
+ nouveau_irq_register(dev, 25, nvc0_runk140_isr);
+
+ if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
+ nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
+ nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
+ nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
+ ret = 0;
+ goto error;
+ }
+
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+ if (ret)
+ goto error;
+
+ for (i = 0; i < 0x1000; i += 4) {
+ nv_wo32(priv->unk4188b4, i, 0x00000010);
+ nv_wo32(priv->unk4188b8, i, 0x00000010);
+ }
+
+ priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f;
+ priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
+ priv->tp_total += priv->tp_nr[gpc];
+ }
+
+ /*XXX: these need figuring out... */
+ switch (dev_priv->chipset) {
+ case 0xc0:
+ if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
+ priv->magic_not_rop_nr = 0x07;
+ /* filled values up to tp_total, the rest 0 */
+ priv->magicgpc918 = 0x000ba2e9;
+ } else
+ if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
+ priv->magic_not_rop_nr = 0x05;
+ priv->magicgpc918 = 0x00092493;
+ } else
+ if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
+ priv->magic_not_rop_nr = 0x06;
+ priv->magicgpc918 = 0x00088889;
+ }
+ break;
+ case 0xc3: /* 450, 4/0/0/0, 2 */
+ priv->magic_not_rop_nr = 0x03;
+ priv->magicgpc918 = 0x00200000;
+ break;
+ case 0xc4: /* 460, 3/4/0/0, 4 */
+ priv->magic_not_rop_nr = 0x01;
+ priv->magicgpc918 = 0x00124925;
+ break;
+ }
+
+ if (!priv->magic_not_rop_nr) {
+ NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
+ priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
+ priv->tp_nr[3], priv->rop_nr);
+ /* use 0xc3's values... */
+ priv->magic_not_rop_nr = 0x03;
+ priv->magicgpc918 = 0x00200000;
+ }
+
+ NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
+ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
+ NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
+ NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
+ NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
+ return 0;
+
+error:
+ nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
+ return ret;
+}
+
+MODULE_FIRMWARE("nouveau/nvc0_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc0_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ad");
+MODULE_FIRMWARE("nouveau/fuc409c");
+MODULE_FIRMWARE("nouveau/fuc409d");
+MODULE_FIRMWARE("nouveau/fuc41ac");
+MODULE_FIRMWARE("nouveau/fuc41ad");
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h
index 40e26f9c56c4..f5d184e0689d 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.h
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.h
@@ -28,13 +28,25 @@
#define GPC_MAX 4
#define TP_MAX 32
-#define ROP_BCAST(r) (0x408800 + (r))
-#define ROP_UNIT(u,r) (0x410000 + (u) * 0x400 + (r))
-#define GPC_BCAST(r) (0x418000 + (r))
-#define GPC_UNIT(t,r) (0x500000 + (t) * 0x8000 + (r))
-#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+#define ROP_BCAST(r) (0x408800 + (r))
+#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r) (0x418000 + (r))
+#define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r))
+#define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct nvc0_graph_fuc {
+ u32 *data;
+ u32 size;
+};
struct nvc0_graph_priv {
+ struct nouveau_exec_engine base;
+
+ struct nvc0_graph_fuc fuc409c;
+ struct nvc0_graph_fuc fuc409d;
+ struct nvc0_graph_fuc fuc41ac;
+ struct nvc0_graph_fuc fuc41ad;
+
u8 gpc_nr;
u8 rop_nr;
u8 tp_nr[GPC_MAX];
@@ -46,15 +58,14 @@ struct nvc0_graph_priv {
struct nouveau_gpuobj *unk4188b8;
u8 magic_not_rop_nr;
- u32 magicgpc980[4];
u32 magicgpc918;
};
struct nvc0_graph_chan {
struct nouveau_gpuobj *grctx;
- struct nouveau_gpuobj *unk408004; // 0x418810 too
- struct nouveau_gpuobj *unk40800c; // 0x419004 too
- struct nouveau_gpuobj *unk418810; // 0x419848 too
+ struct nouveau_gpuobj *unk408004; /* 0x418810 too */
+ struct nouveau_gpuobj *unk40800c; /* 0x419004 too */
+ struct nouveau_gpuobj *unk418810; /* 0x419848 too */
struct nouveau_gpuobj *mmio;
int mmio_nr;
};
diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c
index f880ff776db8..6df066114133 100644
--- a/drivers/gpu/drm/nouveau/nvc0_grctx.c
+++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c
@@ -1623,7 +1623,7 @@ nvc0_grctx_generate_rop(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- // ROPC_BROADCAST
+ /* ROPC_BROADCAST */
nv_wr32(dev, 0x408800, 0x02802a3c);
nv_wr32(dev, 0x408804, 0x00000040);
nv_wr32(dev, 0x408808, 0x0003e00d);
@@ -1647,7 +1647,7 @@ nvc0_grctx_generate_gpc(struct drm_device *dev)
{
int i;
- // GPC_BROADCAST
+ /* GPC_BROADCAST */
nv_wr32(dev, 0x418380, 0x00000016);
nv_wr32(dev, 0x418400, 0x38004e00);
nv_wr32(dev, 0x418404, 0x71e0ffff);
@@ -1728,7 +1728,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- // GPC_BROADCAST.TP_BROADCAST
+ /* GPC_BROADCAST.TP_BROADCAST */
nv_wr32(dev, 0x419848, 0x00000000);
nv_wr32(dev, 0x419864, 0x0000012a);
nv_wr32(dev, 0x419888, 0x00000000);
@@ -1741,7 +1741,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
nv_wr32(dev, 0x419a1c, 0x00000000);
nv_wr32(dev, 0x419a20, 0x00000800);
if (dev_priv->chipset != 0xc0)
- nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3
+ nv_wr32(dev, 0x00419ac4, 0x0007f440); /* 0xc3 */
nv_wr32(dev, 0x419b00, 0x0a418820);
nv_wr32(dev, 0x419b04, 0x062080e6);
nv_wr32(dev, 0x419b08, 0x020398a4);
@@ -1797,8 +1797,8 @@ int
nvc0_grctx_generate(struct nouveau_channel *chan)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
int i, gpc, tp, id;
u32 r000260, tmp;
@@ -1912,13 +1912,13 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
for (i = 1; i < 7; i++)
data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
- // GPC_BROADCAST
+ /* GPC_BROADCAST */
nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) |
priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
nv_wr32(dev, 0x418b08 + (i * 4), data[i]);
- // GPC_BROADCAST.TP_BROADCAST
+ /* GPC_BROADCAST.TP_BROADCAST */
nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) |
priv->magic_not_rop_nr |
data2[0]);
@@ -1926,7 +1926,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
for (i = 0; i < 6; i++)
nv_wr32(dev, 0x419b00 + (i * 4), data[i]);
- // UNK78xx
+ /* UNK78xx */
nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) |
priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
@@ -1944,7 +1944,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
gpc = -1;
for (i = 0, gpc = -1; i < 32; i++) {
int ltp = i * (priv->tp_total - 1) / 32;
-
+
do {
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpnr[gpc]);