mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-12 03:26:26 +00:00
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() ...
This commit is contained in:
commit
46f2b60734
44 changed files with 5086 additions and 1852 deletions
|
@ -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 \
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
|
||||
|
||||
if (oc->id != class)
|
||||
continue;
|
||||
|
||||
if (oc->engine == NVOBJ_ENGINE_SW)
|
||||
return nouveau_gpuobj_sw_new(chan, handle, class);
|
||||
|
||||
if (!chan->engctx[oc->engine]) {
|
||||
ret = eng->context_new(chan, oc->engine);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return eng->object_new(chan, oc->engine, handle, class);
|
||||
}
|
||||
|
||||
NV_ERROR(dev, "illegal object class: 0x%x\n", class);
|
||||
return -EINVAL;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
ret = pcrypt->create_context(chan);
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 @@ nouveau_card_init(struct drm_device *dev)
|
|||
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
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 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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
|
||||
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 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);
|
||||
}
|
||||
nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
|
||||
|
||||
int
|
||||
nv20_graph_load_context(struct nouveau_channel *chan)
|
||||
{
|
||||
struct drm_device *dev = chan->dev;
|
||||
uint32_t inst;
|
||||
|
||||
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;
|
||||
}
|
||||
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
|
||||
|
||||
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->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)
|
||||
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, 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,40 +101,7 @@ 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)
|
||||
{
|
||||
struct drm_device *dev = chan->dev;
|
||||
uint32_t inst;
|
||||
int ret;
|
||||
|
||||
if (!chan->ramin_grctx)
|
||||
return -EINVAL;
|
||||
inst = chan->ramin_grctx->pinst >> 4;
|
||||
|
||||
ret = nv40_graph_transfer_context(dev, inst, 0);
|
||||
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
|
||||
*/
|
||||
nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
nv40_graph_unload_context(struct drm_device *dev)
|
||||
{
|
||||
uint32_t inst;
|
||||
|
@ -204,7 +118,98 @@ nv40_graph_unload_context(struct drm_device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
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 = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
|
||||
NVOBJ_FLAG_ZERO_ALLOC, &grctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
nv40_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;
|
||||
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 (nv40_graph_channel(dev) == chan)
|
||||
nv40_graph_unload_context(dev);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
311
drivers/gpu/drm/nouveau/nv40_mpeg.c
Normal file
311
drivers/gpu/drm/nouveau/nv40_mpeg.c
Normal file
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
nv50_graph_object_new(struct nouveau_channel *chan, int engine,
|
||||
u32 handle, u16 class)
|
||||
{
|
||||
uint32_t fifo = nv_rd32(dev, 0x400500);
|
||||
struct drm_device *dev = chan->dev;
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_gpuobj *obj = NULL;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
|
||||
if (ret)
|
||||
return ret;
|
||||
obj->engine = 1;
|
||||
obj->class = class;
|
||||
|
||||
if (nouveau_wait_for_idle(dev))
|
||||
nv_wr32(dev, 0x40032c, inst | (1<<31));
|
||||
nv_wr32(dev, 0x400500, fifo);
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
256
drivers/gpu/drm/nouveau/nv50_mpeg.c
Normal file
256
drivers/gpu/drm/nouveau/nv50_mpeg.c
Normal file
|
@ -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;
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,45 +82,41 @@ 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);
|
||||
|
||||
atomic_dec(&chan->vm->engref[engine]);
|
||||
chan->engctx[engine] = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nv84_crypt_tlb_flush(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_gpuobj *obj = NULL;
|
||||
int ret;
|
||||
|
||||
ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
|
||||
if (ret)
|
||||
return ret;
|
||||
obj->engine = 5;
|
||||
obj->class = class;
|
||||
|
||||
nv_wo32(obj, 0x00, class);
|
||||
dev_priv->engine.instmem.flush(dev);
|
||||
|
||||
ret = nouveau_ramht_insert(chan, handle, obj);
|
||||
nouveau_gpuobj_ref(NULL, &obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
|
||||
{
|
||||
nv50_vm_flush_engine(dev, 0x0a);
|
||||
}
|
||||
|
||||
int
|
||||
nv84_crypt_init(struct drm_device *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;
|
||||
}
|
||||
|
||||
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
|
||||
nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
|
||||
|
||||
nouveau_irq_register(dev, 14, nv84_crypt_isr);
|
||||
nv_wr32(dev, 0x102130, 0xffffffff);
|
||||
nv_wr32(dev, 0x102140, 0xffffffbf);
|
||||
|
||||
nv_wr32(dev, 0x10200c, 0x00000010);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv84_crypt_fini(struct drm_device *dev)
|
||||
{
|
||||
nv_wr32(dev, 0x102140, 0x00000000);
|
||||
nouveau_irq_unregister(dev, 14);
|
||||
}
|
||||
|
||||
static void
|
||||
nv84_crypt_isr(struct drm_device *dev)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
226
drivers/gpu/drm/nouveau/nva3_copy.c
Normal file
226
drivers/gpu/drm/nouveau/nva3_copy.c
Normal file
|
@ -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;
|
||||
}
|
870
drivers/gpu/drm/nouveau/nva3_copy.fuc
Normal file
870
drivers/gpu/drm/nouveau/nva3_copy.fuc
Normal file
|
@ -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
|
534
drivers/gpu/drm/nouveau/nva3_copy.fuc.h
Normal file
534
drivers/gpu/drm/nouveau/nva3_copy.fuc.h
Normal file
|
@ -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,
|
||||
};
|
|
@ -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;
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = get_pll_limits(dev, id, &state->pll);
|
||||
if (ret < 0) {
|
||||
kfree(state);
|
||||
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);
|
||||
|
||||
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
|
||||
kfree(state);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
kfree(pll);
|
||||
}
|
||||
|
||||
|
|
243
drivers/gpu/drm/nouveau/nvc0_copy.c
Normal file
243
drivers/gpu/drm/nouveau/nvc0_copy.c
Normal file
|
@ -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;
|
||||
}
|
527
drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
Normal file
527
drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
Normal file
|
@ -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,
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 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_chan *grch;
|
||||
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 nvc0_graph_priv *priv = nv_engine(dev, engine);
|
||||
struct nvc0_graph_chan *grch;
|
||||
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
|
||||
struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
|
||||
u32 data[TP_MAX / 8];
|
||||
u8 tpnr[GPC_MAX];
|
||||
int i, gpc, tpc;
|
||||
|
||||
// magicgpc918
|
||||
// 450: 00200000 00000000001000000000000000000000
|
||||
// 460: 00124925 00000000000100100100100100100101
|
||||
// 465: 000ba2e9 00000000000010111010001011101001
|
||||
// 470: 00092493 00000000000010010010010010010011
|
||||
// 480: 00088889 00000000000010001000100010001001
|
||||
/*
|
||||
* 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]);
|
||||
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");
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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]);
|
||||
|
|
Loading…
Reference in a new issue