Commit 46f2b607 authored by Dave Airlie's avatar Dave Airlie

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()
  ...
parents 69f7876b b4fa9d0f
......@@ -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);
......
This diff is collapsed.
......@@ -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;
}
NV_ERROR(dev, "illegal object class: 0x%x\n", class);
return -EINVAL;
struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
found:
switch (oc->engine) {
case NVOBJ_ENGINE_SW:
if (dev_priv->card_type < NV_C0) {
ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj);
if (ret)
return ret;
goto insert;
}
break;
case NVOBJ_ENGINE_GR:
if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) ||
(dev_priv->card_type < NV_20 && !chan->pgraph_ctx)) {
struct nouveau_pgraph_engine *pgraph =
&dev_priv->engine.graph;
if (oc->id != class)
continue;
ret = pgraph->create_context(chan);
if (ret)
return ret;
}
break;
case NVOBJ_ENGINE_CRYPT:
if (!chan->crypt_ctx) {
struct nouveau_crypt_engine *pcrypt =
&dev_priv->engine.crypt;
if (oc->engine == NVOBJ_ENGINE_SW)
return nouveau_gpuobj_sw_new(chan, handle, class);
ret = pcrypt->create_context(chan);
if (!chan->engctx[oc->engine]) {
ret = eng->context_new(chan, oc->engine);
if (ret)
return ret;
}
break;
}
/* we're done if this is fermi */
if (dev_priv->card_type >= NV_C0)
return 0;
ret = nouveau_gpuobj_new(dev, chan,
nouveau_gpuobj_class_instmem_size(dev, class),
16,
NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
&gpuobj);
if (ret) {
NV_ERROR(dev, "error creating gpuobj: %d\n", ret);
return ret;
}
if (dev_priv->card_type >= NV_50) {
nv_wo32(gpuobj, 0, class);
nv_wo32(gpuobj, 20, 0x00010000);
} else {
switch (class) {
case NV_CLASS_NULL:
nv_wo32(gpuobj, 0, 0x00001030);
nv_wo32(gpuobj, 4, 0xFFFFFFFF);
break;
default:
if (dev_priv->card_type >= NV_40) {
nv_wo32(gpuobj, 0, class);
#ifdef __BIG_ENDIAN
nv_wo32(gpuobj, 8, 0x01000000);
#endif
} else {
#ifdef __BIG_ENDIAN
nv_wo32(gpuobj, 0, class | 0x00080000);
#else
nv_wo32(gpuobj, 0, class);
#endif
}
}
return eng->object_new(chan, oc->engine, handle, class);
}
dev_priv->engine.instmem.flush(dev);
gpuobj->engine = oc->engine;
gpuobj->class = oc->id;
insert:
ret = nouveau_ramht_insert(chan, handle, gpuobj);
if (ret)
NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret);
nouveau_gpuobj_ref(NULL, &gpuobj);
return ret;
NV_ERROR(dev, "illegal object class: 0x%x\n", class);
return -EINVAL;
}
static int
......@@ -746,9 +663,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
size = 0x2000;
base = 0;
/* PGRAPH context */
size += dev_priv->engine.graph.grctx_size;
if (dev_priv->card_type == NV_50) {
/* Various fixed table thingos */
size += 0x1400; /* mostly unknown stuff */
......
......@@ -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)
......
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
......@@ -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
......
This diff is collapsed.
This diff is collapsed.
......@@ -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,
......
This diff is collapsed.
/*
* 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) &&
......
This diff is collapsed.
......@@ -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 */
......
/*
* 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,43 +82,39 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
nv_wr32(dev, 0x10200c, 0x00000010);
nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
atomic_dec(&chan->vm->pcrypt_refs);
}
nouveau_gpuobj_ref(NULL, &ctx);
void
nv84_crypt_tlb_flush(struct drm_device *dev)
{
nv50_vm_flush_engine(dev, 0x0a);
atomic_dec(&chan->vm->engref[engine]);
chan->engctx[engine] = NULL;
}
int
nv84_crypt_init(struct drm_device *dev)
static int
nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
u32 handle, u16 class)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
if (!pcrypt->registered) {
NVOBJ_CLASS(dev, 0x74c1, CRYPT);
pcrypt->registered = true;
}
struct nouveau_gpuobj *obj = NULL;
int ret;
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
if (ret)
return ret;
obj->engine = 5;
obj->class = class;
nouveau_irq_register(dev, 14, nv84_crypt_isr);
nv_wr32(dev, 0x102130, 0xffffffff);
nv_wr32(dev, 0x102140, 0xffffffbf);
nv_wo32(obj, 0x00, class);
dev_priv->engine.instmem.flush(dev);
nv_wr32(dev, 0x10200c, 0x00000010);
return 0;
ret = nouveau_ramht_insert(chan, handle, obj);
nouveau_gpuobj_ref(NULL, &obj);
return ret;
}
void
nv84_crypt_fini(struct drm_device *dev)
static void
nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
{
nv_wr32(dev, 0x102140, 0x00000000);
nouveau_irq_unregister(dev, 14);
nv50_vm_flush_engine(dev, 0x0a);
}
static void
......@@ -138,3 +136,58 @@ nv84_crypt_isr(struct drm_device *dev)
nv50_fb_vm_trap(dev, show);
}
static int
nv84_crypt_fini(struct drm_device *dev, int engine)
{
nv_wr32(dev, 0x102140, 0x00000000);
return 0;
}
static int
nv84_crypt_init(struct drm_device *dev, int engine)
{
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
nv_wr32(dev, 0x102130, 0xffffffff);
nv_wr32(dev, 0x102140, 0xffffffbf);
nv_wr32(dev, 0x10200c, 0x00000010);
return 0;
}
static void
nv84_crypt_destroy(struct drm_device *dev, int engine)
{
struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
NVOBJ_ENGINE_DEL(dev, CRYPT);
nouveau_irq_unregister(dev, 14);
kfree(pcrypt);
}
int
nv84_crypt_create(struct drm_device *dev)
{
struct nv84_crypt_engine *pcrypt;
pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
if (!pcrypt)
return -ENOMEM;
pcrypt->base.destroy = nv84_crypt_destroy;
pcrypt->base.init = nv84_crypt_init;
pcrypt->base.fini = nv84_crypt_fini;
pcrypt->base.context_new = nv84_crypt_context_new;
pcrypt->base.context_del = nv84_crypt_context_del;
pcrypt->base.object_new = nv84_crypt_object_new;
pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
nouveau_irq_register(dev, 14, nv84_crypt_isr);
NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
NVOBJ_CLASS (dev, 0x74c1, CRYPT);
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment