Commit 042206c0 authored by Francisco Jerez's avatar Francisco Jerez Committed by Ben Skeggs

drm/nouveau: Implement the vblank DRM hooks.

Signed-off-by: default avatarFrancisco Jerez <currojerez@riseup.net>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 63f7fcfe
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "nouveau_drv.h" #include "nouveau_drv.h"
#include "nouveau_fb.h" #include "nouveau_fb.h"
#include "nouveau_fbcon.h" #include "nouveau_fbcon.h"
#include "nouveau_hw.h"
static void static void
nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
...@@ -104,3 +105,29 @@ const struct drm_mode_config_funcs nouveau_mode_config_funcs = { ...@@ -104,3 +105,29 @@ const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
.output_poll_changed = nouveau_fbcon_output_poll_changed, .output_poll_changed = nouveau_fbcon_output_poll_changed,
}; };
int
nouveau_vblank_enable(struct drm_device *dev, int crtc)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (dev_priv->card_type >= NV_50)
nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc));
else
NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0,
NV_PCRTC_INTR_0_VBLANK);
return 0;
}
void
nouveau_vblank_disable(struct drm_device *dev, int crtc)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (dev_priv->card_type >= NV_50)
nv_mask(dev, NV50_PDISPLAY_INTR_EN_1,
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0);
else
NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0);
}
...@@ -397,6 +397,9 @@ static struct drm_driver driver = { ...@@ -397,6 +397,9 @@ static struct drm_driver driver = {
.irq_postinstall = nouveau_irq_postinstall, .irq_postinstall = nouveau_irq_postinstall,
.irq_uninstall = nouveau_irq_uninstall, .irq_uninstall = nouveau_irq_uninstall,
.irq_handler = nouveau_irq_handler, .irq_handler = nouveau_irq_handler,
.get_vblank_counter = drm_vblank_count,
.enable_vblank = nouveau_vblank_enable,
.disable_vblank = nouveau_vblank_disable,
.reclaim_buffers = drm_core_reclaim_buffers, .reclaim_buffers = drm_core_reclaim_buffers,
.ioctls = nouveau_ioctls, .ioctls = nouveau_ioctls,
.fops = { .fops = {
...@@ -407,6 +410,7 @@ static struct drm_driver driver = { ...@@ -407,6 +410,7 @@ static struct drm_driver driver = {
.mmap = nouveau_ttm_mmap, .mmap = nouveau_ttm_mmap,
.poll = drm_poll, .poll = drm_poll,
.fasync = drm_fasync, .fasync = drm_fasync,
.read = drm_read,
#if defined(CONFIG_COMPAT) #if defined(CONFIG_COMPAT)
.compat_ioctl = nouveau_compat_ioctl, .compat_ioctl = nouveau_compat_ioctl,
#endif #endif
......
...@@ -1312,6 +1312,10 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, ...@@ -1312,6 +1312,10 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
extern int nouveau_gem_ioctl_info(struct drm_device *, void *, extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
struct drm_file *); struct drm_file *);
/* nouveau_display.c */
int nouveau_vblank_enable(struct drm_device *dev, int crtc);
void nouveau_vblank_disable(struct drm_device *dev, int crtc);
/* nv10_gpio.c */ /* nv10_gpio.c */
int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
......
...@@ -1017,8 +1017,9 @@ nv_load_state_ext(struct drm_device *dev, int head, ...@@ -1017,8 +1017,9 @@ nv_load_state_ext(struct drm_device *dev, int head,
NVWriteCRTC(dev, head, NV_PCRTC_START, regp->fb_start); NVWriteCRTC(dev, head, NV_PCRTC_START, regp->fb_start);
/* Setting 1 on this value gives you interrupts for every vblank period. */ /* Enable vblank interrupts. */
NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0, 0); NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0,
(dev->vblank_enabled[head] ? 1 : 0));
NVWriteCRTC(dev, head, NV_PCRTC_INTR_0, NV_PCRTC_INTR_0_VBLANK); NVWriteCRTC(dev, head, NV_PCRTC_INTR_0, NV_PCRTC_INTR_0_VBLANK);
} }
......
...@@ -1200,11 +1200,15 @@ nv50_pgraph_irq_handler(struct drm_device *dev) ...@@ -1200,11 +1200,15 @@ nv50_pgraph_irq_handler(struct drm_device *dev)
static void static void
nouveau_crtc_irq_handler(struct drm_device *dev, int crtc) nouveau_crtc_irq_handler(struct drm_device *dev, int crtc)
{ {
if (crtc & 1) if (crtc & 1) {
nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK);
drm_handle_vblank(dev, 0);
}
if (crtc & 2) if (crtc & 2) {
nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK);
drm_handle_vblank(dev, 1);
}
} }
irqreturn_t irqreturn_t
......
...@@ -669,13 +669,13 @@ nouveau_card_init(struct drm_device *dev) ...@@ -669,13 +669,13 @@ nouveau_card_init(struct drm_device *dev)
if (ret) if (ret)
goto out_fifo; goto out_fifo;
ret = nouveau_irq_init(dev); ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1);
if (ret) if (ret)
goto out_display; goto out_vblank;
ret = drm_vblank_init(dev, 0); ret = nouveau_irq_init(dev);
if (ret) if (ret)
goto out_irq; goto out_vblank;
/* what about PVIDEO/PCRTC/PRAMDAC etc? */ /* what about PVIDEO/PCRTC/PRAMDAC etc? */
...@@ -701,7 +701,8 @@ nouveau_card_init(struct drm_device *dev) ...@@ -701,7 +701,8 @@ nouveau_card_init(struct drm_device *dev)
nouveau_fence_fini(dev); nouveau_fence_fini(dev);
out_irq: out_irq:
nouveau_irq_fini(dev); nouveau_irq_fini(dev);
out_display: out_vblank:
drm_vblank_cleanup(dev);
engine->display.destroy(dev); engine->display.destroy(dev);
out_fifo: out_fifo:
if (!nouveau_noaccel) if (!nouveau_noaccel)
...@@ -772,6 +773,7 @@ static void nouveau_card_takedown(struct drm_device *dev) ...@@ -772,6 +773,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
nouveau_mem_vram_fini(dev); nouveau_mem_vram_fini(dev);
nouveau_irq_fini(dev); nouveau_irq_fini(dev);
drm_vblank_cleanup(dev);
nouveau_pm_fini(dev); nouveau_pm_fini(dev);
nouveau_bios_takedown(dev); nouveau_bios_takedown(dev);
......
...@@ -428,31 +428,29 @@ static void ...@@ -428,31 +428,29 @@ static void
nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc) nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan; struct nouveau_channel *chan, *tmp;
struct list_head *entry, *tmp;
list_for_each_safe(entry, tmp, &dev_priv->vbl_waiting) {
chan = list_entry(entry, struct nouveau_channel, nvsw.vbl_wait);
list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
nvsw.vbl_wait) {
nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset, nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
chan->nvsw.vblsem_rval); chan->nvsw.vblsem_rval);
list_del(&chan->nvsw.vbl_wait); list_del(&chan->nvsw.vbl_wait);
drm_vblank_put(dev, crtc);
} }
drm_handle_vblank(dev, crtc);
} }
static void static void
nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
{ {
intr &= NV50_PDISPLAY_INTR_1_VBLANK_CRTC;
if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0) if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0)
nv50_display_vblank_crtc_handler(dev, 0); nv50_display_vblank_crtc_handler(dev, 0);
if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1) if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1)
nv50_display_vblank_crtc_handler(dev, 1); nv50_display_vblank_crtc_handler(dev, 1);
nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, intr, 0x00000000); nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC);
nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr);
} }
static void static void
......
...@@ -384,14 +384,7 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, ...@@ -384,14 +384,7 @@ nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1) if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1)
return -EINVAL; return -EINVAL;
if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN_1) & drm_vblank_get(dev, data);
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data))) {
nv_wr32(dev, NV50_PDISPLAY_INTR_1,
NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data));
nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0,
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(data));
}
list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting); list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting);
return 0; return 0;
} }
......
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