nouveau_mxm.o nouveau_agp.o \
nouveau_abi16.o \
nouveau_bios.o \
- nv04_fence.o nv10_fence.o nv84_fence.o nvc0_fence.o \
+ nv04_fence.o nv10_fence.o nv50_fence.o nv84_fence.o nvc0_fence.o \
nv04_software.o nv50_software.o nvc0_software.o \
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
nv04_crtc.o nv04_display.o nv04_cursor.o \
#include "nouveau_drv.h"
#include <core/mm.h>
#include <engine/fifo.h>
+#include "nouveau_software.h"
static void nvc0_fifo_isr(struct drm_device *);
spin_lock_irqsave(&dev_priv->channels.lock, flags);
if (likely(chid >= 0 && chid < priv->base.channels)) {
chan = dev_priv->channels.ptr[chid];
- if (likely(chan))
- ret = nouveau_finish_page_flip(chan, NULL);
+ if (likely(chan)) {
+ struct nouveau_software_chan *swch =
+ chan->engctx[NVOBJ_ENGINE_SW];
+ ret = swch->flip(swch->flip_data);
+ }
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
return ret;
#include "nouveau_drv.h"
#include <core/mm.h>
#include <engine/fifo.h>
+#include "nouveau_software.h"
#define NVE0_FIFO_ENGINE_NUM 32
spin_lock_irqsave(&dev_priv->channels.lock, flags);
if (likely(chid >= 0 && chid < priv->base.channels)) {
chan = dev_priv->channels.ptr[chid];
- if (likely(chan))
- ret = nouveau_finish_page_flip(chan, NULL);
+ if (likely(chan)) {
+ struct nouveau_software_chan *swch =
+ chan->engctx[NVOBJ_ENGINE_SW];
+ ret = swch->flip(swch->flip_data);
+ }
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
return ret;
u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000));
u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000));
u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000));
- u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
+ u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0xfff;
u32 subc = (addr & 0x00070000);
u32 mthd = (addr & 0x00003ffc);
u32 show = stat;
struct nouveau_page_flip_state *s,
struct nouveau_fence **pfence)
{
- struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
+ struct nouveau_fence_chan *fctx = chan->fence;
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
unsigned long flags;
/* Queue it to the pending list */
spin_lock_irqsave(&dev->event_lock, flags);
- list_add_tail(&s->head, &swch->flip);
+ list_add_tail(&s->head, &fctx->flip);
spin_unlock_irqrestore(&dev->event_lock, flags);
/* Synchronize with the old framebuffer */
nouveau_finish_page_flip(struct nouveau_channel *chan,
struct nouveau_page_flip_state *ps)
{
- struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
+ struct nouveau_fence_chan *fctx = chan->fence;
struct drm_device *dev = chan->dev;
struct nouveau_page_flip_state *s;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
- if (list_empty(&swch->flip)) {
+ if (list_empty(&fctx->flip)) {
NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
spin_unlock_irqrestore(&dev->event_lock, flags);
return -EINVAL;
}
- s = list_first_entry(&swch->flip, struct nouveau_page_flip_state, head);
+ s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
if (s->event) {
struct drm_pending_vblank_event *e = s->event;
struct timeval now;
return 0;
}
+int
+nouveau_flip_complete(void *data)
+{
+ struct nouveau_channel *chan = data;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_page_flip_state state;
+
+ if (!nouveau_finish_page_flip(chan, &state)) {
+ if (dev_priv->card_type < NV_50) {
+ nv_set_crtc_base(dev, state.crtc, state.offset +
+ state.y * state.pitch +
+ state.x * state.bpp / 8);
+ }
+ }
+
+ return 0;
+}
+
int
nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
struct drm_mode_create_dumb *args)
void
nouveau_fence_context_new(struct nouveau_fence_chan *fctx)
{
+ INIT_LIST_HEAD(&fctx->flip);
INIT_LIST_HEAD(&fctx->pending);
spin_lock_init(&fctx->lock);
}
struct nouveau_fence_chan {
struct list_head pending;
+ struct list_head flip;
+
spinlock_t lock;
u32 sequence;
};
int nv04_fence_create(struct drm_device *dev);
int nv04_fence_mthd(struct nouveau_channel *, u32, u32, u32);
-int nv10_fence_create(struct drm_device *dev);
+int nv10_fence_emit(struct nouveau_fence *);
+int nv17_fence_sync(struct nouveau_fence *, struct nouveau_channel *,
+ struct nouveau_channel *);
+u32 nv10_fence_read(struct nouveau_channel *);
+void nv10_fence_context_del(struct nouveau_channel *);
+void nv10_fence_destroy(struct drm_device *);
+int nv10_fence_create(struct drm_device *dev);
+
+int nv50_fence_create(struct drm_device *dev);
int nv84_fence_create(struct drm_device *dev);
int nvc0_fence_create(struct drm_device *dev);
+u64 nvc0_fence_crtc(struct nouveau_channel *, int crtc);
+
+int nouveau_flip_complete(void *chan);
#endif
#ifndef __NOUVEAU_SOFTWARE_H__
#define __NOUVEAU_SOFTWARE_H__
+#include "nouveau_fence.h"
+
struct nouveau_software_priv {
struct nouveau_exec_engine base;
struct list_head vblank;
};
struct nouveau_software_chan {
- struct list_head flip;
+ int (*flip)(void *data);
+ void *flip_data;
+
struct {
struct list_head list;
u32 channel;
};
static inline void
-nouveau_software_context_new(struct nouveau_software_chan *pch)
+nouveau_software_context_new(struct nouveau_channel *chan,
+ struct nouveau_software_chan *pch)
{
- INIT_LIST_HEAD(&pch->flip);
- INIT_LIST_HEAD(&pch->vblank.list);
+ pch->flip = nouveau_flip_complete;
+ pch->flip_data = chan;
}
static inline void
int nv04_software_create(struct drm_device *);
int nv50_software_create(struct drm_device *);
int nvc0_software_create(struct drm_device *);
-u64 nvc0_software_crtc(struct nouveau_channel *, int crtc);
#endif
case NV_40:
case NV_50:
if (dev_priv->chipset < 0x84)
- nv10_fence_create(dev);
+ nv50_fence_create(dev);
else
nv84_fence_create(dev);
break;
static int
mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
{
-
- struct nouveau_page_flip_state state;
-
- if (!nouveau_finish_page_flip(chan, &state)) {
- nv_set_crtc_base(chan->dev, state.crtc, state.offset +
- state.y * state.pitch +
- state.x * state.bpp / 8);
- }
-
- return 0;
+ struct nv04_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+ return pch->base.flip(pch->base.flip_data);
}
static int
if (!pch)
return -ENOMEM;
- nouveau_software_context_new(&pch->base);
+ nouveau_software_context_new(chan, &pch->base);
chan->engctx[engine] = pch;
return 0;
}
u32 sequence;
};
-static int
+int
nv10_fence_emit(struct nouveau_fence *fence)
{
struct nouveau_channel *chan = fence->channel;
return -ENODEV;
}
-static int
+int
nv17_fence_sync(struct nouveau_fence *fence,
struct nouveau_channel *prev, struct nouveau_channel *chan)
{
return 0;
}
-static u32
+u32
nv10_fence_read(struct nouveau_channel *chan)
{
return nvchan_rd32(chan, 0x0048);
}
-static void
+void
nv10_fence_context_del(struct nouveau_channel *chan)
{
struct nv10_fence_chan *fctx = chan->fence;
return ret;
}
-static void
+void
nv10_fence_destroy(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
#include "nouveau_fb.h"
#include "nouveau_fbcon.h"
#include <core/ramht.h>
-#include "nouveau_software.h"
#include "drm_crtc_helper.h"
+#include "nouveau_fence.h"
static void nv50_display_isr(struct drm_device *);
static void nv50_display_bh(unsigned long);
else
OUT_RING (chan, chan->vram_handle);
} else {
- u64 offset = nvc0_software_crtc(chan, nv_crtc->index);
+ u64 offset = nvc0_fence_crtc(chan, nv_crtc->index);
offset += dispc->sem.offset;
BEGIN_NVC0(chan, 0, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
--- /dev/null
+/*
+ * Copyright 2012 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 <bskeggs@redhat.com>
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_dma.h"
+#include <core/ramht.h>
+#include "nouveau_fence.h"
+#include "nv50_display.h"
+
+struct nv50_fence_chan {
+ struct nouveau_fence_chan base;
+};
+
+struct nv50_fence_priv {
+ struct nouveau_fence_priv base;
+ struct nouveau_bo *bo;
+ spinlock_t lock;
+ u32 sequence;
+};
+
+static int
+nv50_fence_context_new(struct nouveau_channel *chan)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nv50_fence_priv *priv = dev_priv->fence.func;
+ struct nv50_fence_chan *fctx;
+ struct ttm_mem_reg *mem = &priv->bo->bo.mem;
+ struct nouveau_gpuobj *obj;
+ int ret = 0, i;
+
+ fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+
+ nouveau_fence_context_new(&fctx->base);
+
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
+ mem->start * PAGE_SIZE, mem->size,
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &obj);
+ if (!ret) {
+ ret = nouveau_ramht_insert(chan, NvSema, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ }
+
+ /* dma objects for display sync channel semaphore blocks */
+ for (i = 0; i < chan->dev->mode_config.num_crtc; i++) {
+ struct nv50_display *pdisp = nv50_display(chan->dev);
+ struct nv50_display_crtc *dispc = &pdisp->crtc[i];
+ struct nouveau_gpuobj *obj = NULL;
+
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+ dispc->sem.bo->bo.offset, 0x1000,
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &obj);
+ if (ret)
+ break;
+
+ ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ }
+
+ if (ret)
+ nv10_fence_context_del(chan);
+ return ret;
+}
+
+int
+nv50_fence_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_fence_priv *priv;
+ int ret = 0;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.dtor = nv10_fence_destroy;
+ priv->base.context_new = nv50_fence_context_new;
+ priv->base.context_del = nv10_fence_context_del;
+ priv->base.emit = nv10_fence_emit;
+ priv->base.read = nv10_fence_read;
+ priv->base.sync = nv17_fence_sync;
+ dev_priv->fence.func = &priv->base;
+ spin_lock_init(&priv->lock);
+
+ ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+ 0, 0x0000, NULL, &priv->bo);
+ if (!ret) {
+ ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
+ if (!ret)
+ ret = nouveau_bo_map(priv->bo);
+ if (ret)
+ nouveau_bo_ref(NULL, &priv->bo);
+ }
+
+ if (ret == 0)
+ nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
+ else
+ nv10_fence_destroy(dev);
+ return ret;
+}
static int
mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
{
- nouveau_finish_page_flip(chan, NULL);
- return 0;
+ struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+ return pch->base.flip(pch->base.flip_data);
}
static int
nv50_software_context_new(struct nouveau_channel *chan, int engine)
{
- struct nv50_software_priv *psw = nv_engine(chan->dev, NVOBJ_ENGINE_SW);
- struct nv50_display *pdisp = nv50_display(chan->dev);
struct nv50_software_chan *pch;
- int ret = 0, i;
pch = kzalloc(sizeof(*pch), GFP_KERNEL);
if (!pch)
return -ENOMEM;
- nouveau_software_context_new(&pch->base);
+ nouveau_software_context_new(chan, &pch->base);
pch->base.vblank.channel = chan->ramin->addr >> 12;
chan->engctx[engine] = pch;
-
- /* dma objects for display sync channel semaphore blocks */
- for (i = 0; i < chan->dev->mode_config.num_crtc; i++) {
- struct nv50_display_crtc *dispc = &pdisp->crtc[i];
- struct nouveau_gpuobj *obj = NULL;
-
- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
- dispc->sem.bo->bo.offset, 0x1000,
- NV_MEM_ACCESS_RW,
- NV_MEM_TARGET_VRAM, &obj);
- if (ret)
- break;
-
- ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, obj);
- nouveau_gpuobj_ref(NULL, &obj);
- }
-
- if (ret)
- psw->base.base.context_del(chan, engine);
- return ret;
+ return 0;
}
static void
#include <engine/fifo.h>
#include <core/ramht.h>
#include "nouveau_fence.h"
+#include "nv50_display.h"
struct nv84_fence_chan {
struct nouveau_fence_chan base;
struct nv84_fence_priv *priv = dev_priv->fence.func;
struct nv84_fence_chan *fctx;
struct nouveau_gpuobj *obj;
- int ret;
+ int ret, i;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
nv_wo32(priv->mem, chan->id * 16, 0x00000000);
}
+ /* dma objects for display sync channel semaphore blocks */
+ for (i = 0; i < chan->dev->mode_config.num_crtc; i++) {
+ struct nv50_display *pdisp = nv50_display(chan->dev);
+ struct nv50_display_crtc *dispc = &pdisp->crtc[i];
+ struct nouveau_gpuobj *obj = NULL;
+
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+ dispc->sem.bo->bo.offset, 0x1000,
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &obj);
+ if (ret)
+ break;
+
+ ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ }
+
if (ret)
nv84_fence_context_del(chan);
return ret;
#include <engine/fifo.h>
#include <core/ramht.h>
#include "nouveau_fence.h"
+#include "nv50_display.h"
struct nvc0_fence_priv {
struct nouveau_fence_priv base;
struct nvc0_fence_chan {
struct nouveau_fence_chan base;
struct nouveau_vma vma;
+ struct nouveau_vma dispc_vma[4];
};
+u64
+nvc0_fence_crtc(struct nouveau_channel *chan, int crtc)
+{
+ struct nvc0_fence_chan *fctx = chan->fence;
+ return fctx->dispc_vma[crtc].offset;
+}
+
static int
nvc0_fence_emit(struct nouveau_fence *fence)
{
static void
nvc0_fence_context_del(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvc0_fence_priv *priv = dev_priv->fence.func;
struct nvc0_fence_chan *fctx = chan->fence;
+ int i;
+
+ if (dev_priv->card_type >= NV_D0) {
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ struct nouveau_bo *bo = nvd0_display_crtc_sema(dev, i);
+ nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
+ }
+ } else
+ if (dev_priv->card_type >= NV_50) {
+ struct nv50_display *disp = nv50_display(dev);
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ struct nv50_display_crtc *dispc = &disp->crtc[i];
+ nouveau_bo_vma_del(dispc->sem.bo, &fctx->dispc_vma[i]);
+ }
+ }
nouveau_bo_vma_del(priv->bo, &fctx->vma);
nouveau_fence_context_del(&fctx->base);
static int
nvc0_fence_context_new(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvc0_fence_priv *priv = dev_priv->fence.func;
struct nvc0_fence_chan *fctx;
- int ret;
+ int ret, i;
fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
if (!fctx)
if (ret)
nvc0_fence_context_del(chan);
+ /* map display semaphore buffers into channel's vm */
+ for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
+ struct nouveau_bo *bo;
+ if (dev_priv->card_type >= NV_D0)
+ bo = nvd0_display_crtc_sema(dev, i);
+ else
+ bo = nv50_display(dev)->crtc[i].sem.bo;
+
+ ret = nouveau_bo_vma_add(bo, chan->vm, &fctx->dispc_vma[i]);
+ }
+
nouveau_bo_wr32(priv->bo, chan->id * 16/4, 0x00000000);
return ret;
}
struct nvc0_software_chan {
struct nouveau_software_chan base;
- struct nouveau_vma dispc_vma[4];
};
-u64
-nvc0_software_crtc(struct nouveau_channel *chan, int crtc)
-{
- struct nvc0_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
- return pch->dispc_vma[crtc].offset;
-}
-
static int
nvc0_software_context_new(struct nouveau_channel *chan, int engine)
{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
struct nvc0_software_chan *pch;
- int ret = 0, i;
pch = kzalloc(sizeof(*pch), GFP_KERNEL);
if (!pch)
return -ENOMEM;
- nouveau_software_context_new(&pch->base);
+ nouveau_software_context_new(chan, &pch->base);
chan->engctx[engine] = pch;
-
- /* map display semaphore buffers into channel's vm */
- for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
- struct nouveau_bo *bo;
- if (dev_priv->card_type >= NV_D0)
- bo = nvd0_display_crtc_sema(dev, i);
- else
- bo = nv50_display(dev)->crtc[i].sem.bo;
-
- ret = nouveau_bo_vma_add(bo, chan->vm, &pch->dispc_vma[i]);
- }
-
- if (ret)
- psw->base.base.context_del(chan, engine);
- return ret;
+ return 0;
}
static void
nvc0_software_context_del(struct nouveau_channel *chan, int engine)
{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvc0_software_chan *pch = chan->engctx[engine];
- int i;
-
- if (dev_priv->card_type >= NV_D0) {
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct nouveau_bo *bo = nvd0_display_crtc_sema(dev, i);
- nouveau_bo_vma_del(bo, &pch->dispc_vma[i]);
- }
- } else
- if (dev_priv->card_type >= NV_50) {
- struct nv50_display *disp = nv50_display(dev);
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct nv50_display_crtc *dispc = &disp->crtc[i];
- nouveau_bo_vma_del(dispc->sem.bo, &pch->dispc_vma[i]);
- }
- }
-
chan->engctx[engine] = NULL;
kfree(pch);
}
#include "nouveau_crtc.h"
#include "nouveau_dma.h"
#include "nouveau_fb.h"
-#include "nouveau_software.h"
+#include "nouveau_fence.h"
#include "nv50_display.h"
#define EVO_DMA_NR 9
return ret;
- offset = nvc0_software_crtc(chan, nv_crtc->index);
+ offset = nvc0_fence_crtc(chan, nv_crtc->index);
offset += evo->sem.offset;
BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);