summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/gpu/drm/nouveau/nouveau_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/gpu/drm/nouveau/nouveau_display.c')
-rw-r--r--kernel/drivers/gpu/drm/nouveau/nouveau_display.c87
1 files changed, 52 insertions, 35 deletions
diff --git a/kernel/drivers/gpu/drm/nouveau/nouveau_display.c b/kernel/drivers/gpu/drm/nouveau/nouveau_display.c
index 8670d90cd..58a3f7cf2 100644
--- a/kernel/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/kernel/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -51,12 +51,12 @@ nouveau_display_vblank_handler(struct nvif_notify *notify)
}
int
-nouveau_display_vblank_enable(struct drm_device *dev, int head)
+nouveau_display_vblank_enable(struct drm_device *dev, unsigned int pipe)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- if (nv_crtc->index == head) {
+ if (nv_crtc->index == pipe) {
nvif_notify_get(&nv_crtc->vblank);
return 0;
}
@@ -65,12 +65,12 @@ nouveau_display_vblank_enable(struct drm_device *dev, int head)
}
void
-nouveau_display_vblank_disable(struct drm_device *dev, int head)
+nouveau_display_vblank_disable(struct drm_device *dev, unsigned int pipe)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- if (nv_crtc->index == head) {
+ if (nv_crtc->index == pipe) {
nvif_notify_put(&nv_crtc->vblank);
return;
}
@@ -103,6 +103,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
.base.head = nouveau_crtc(crtc)->index,
};
struct nouveau_display *disp = nouveau_display(crtc->dev);
+ struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
int ret, retry = 1;
do {
@@ -116,7 +117,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
break;
}
- if (retry) ndelay(crtc->linedur_ns);
+ if (retry) ndelay(vblank->linedur_ns);
} while (retry--);
*hpos = args.scan.hline;
@@ -131,13 +132,15 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
}
int
-nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
- int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
+nouveau_display_scanoutpos(struct drm_device *dev, unsigned int pipe,
+ unsigned int flags, int *vpos, int *hpos,
+ ktime_t *stime, ktime_t *etime,
+ const struct drm_display_mode *mode)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- if (nouveau_crtc(crtc)->index == head) {
+ if (nouveau_crtc(crtc)->index == pipe) {
return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
stime, etime);
}
@@ -147,15 +150,15 @@ nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
}
int
-nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error,
- struct timeval *time, unsigned flags)
+nouveau_display_vblstamp(struct drm_device *dev, unsigned int pipe,
+ int *max_error, struct timeval *time, unsigned flags)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- if (nouveau_crtc(crtc)->index == head) {
+ if (nouveau_crtc(crtc)->index == pipe) {
return drm_calc_vbltimestamp_from_scanoutpos(dev,
- head, max_error, time, flags, crtc,
+ pipe, max_error, time, flags,
&crtc->hwmode);
}
}
@@ -185,7 +188,7 @@ nouveau_display_vblank_init(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- ret = nvif_notify_init(&disp->disp, NULL,
+ ret = nvif_notify_init(&disp->disp,
nouveau_display_vblank_handler, false,
NV04_DISP_NTFY_VBLANK,
&(struct nvif_notify_head_req_v0) {
@@ -358,6 +361,7 @@ int
nouveau_display_init(struct drm_device *dev)
{
struct nouveau_display *disp = nouveau_display(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_connector *connector;
int ret;
@@ -374,6 +378,8 @@ nouveau_display_init(struct drm_device *dev)
nvif_notify_get(&conn->hpd);
}
+ /* enable flip completion events */
+ nvif_notify_get(&drm->flip);
return ret;
}
@@ -381,6 +387,7 @@ void
nouveau_display_fini(struct drm_device *dev)
{
struct nouveau_display *disp = nouveau_display(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_connector *connector;
int head;
@@ -388,6 +395,9 @@ nouveau_display_fini(struct drm_device *dev)
for (head = 0; head < dev->mode_config.num_crtc; head++)
drm_vblank_off(dev, head);
+ /* disable flip completion events */
+ nvif_notify_put(&drm->flip);
+
/* disable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector);
@@ -438,6 +448,7 @@ int
nouveau_display_create(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nvkm_device *device = nvxx_device(&drm->device);
struct nouveau_display *disp;
int ret;
@@ -450,7 +461,7 @@ nouveau_display_create(struct drm_device *dev)
drm_mode_create_dvi_i_properties(dev);
dev->mode_config.funcs = &nouveau_mode_config_funcs;
- dev->mode_config.fb_base = nv_device_resource_start(nvxx_device(&drm->device), 1);
+ dev->mode_config.fb_base = device->func->resource_addr(device, 1);
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
@@ -461,9 +472,13 @@ nouveau_display_create(struct drm_device *dev)
if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) {
dev->mode_config.max_width = 4096;
dev->mode_config.max_height = 4096;
- } else {
+ } else
+ if (drm->device.info.family < NV_DEVICE_INFO_V0_FERMI) {
dev->mode_config.max_width = 8192;
dev->mode_config.max_height = 8192;
+ } else {
+ dev->mode_config.max_width = 16384;
+ dev->mode_config.max_height = 16384;
}
dev->mode_config.preferred_depth = 24;
@@ -494,9 +509,8 @@ nouveau_display_create(struct drm_device *dev)
int i;
for (i = 0, ret = -ENODEV; ret && i < ARRAY_SIZE(oclass); i++) {
- ret = nvif_object_init(nvif_object(&drm->device), NULL,
- NVDRM_DISPLAY, oclass[i],
- NULL, 0, &disp->disp);
+ ret = nvif_object_init(&drm->device.object, 0,
+ oclass[i], NULL, 0, &disp->disp);
}
if (ret == 0) {
@@ -620,10 +634,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
nv_crtc->lut.depth = 0;
}
- /* Make sure that drm and hw vblank irqs get resumed if needed. */
- for (head = 0; head < dev->mode_config.num_crtc; head++)
- drm_vblank_on(dev, head);
-
/* This should ensure we don't hit a locking problem when someone
* wakes us up via a connector. We should never go into suspend
* while the display is on anyways.
@@ -633,6 +643,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
drm_helper_resume_force_mode(dev);
+ /* Make sure that drm and hw vblank irqs get resumed if needed. */
+ for (head = 0; head < dev->mode_config.num_crtc; head++)
+ drm_vblank_on(dev, head);
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
@@ -711,7 +725,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
chan = drm->channel;
if (!chan)
return -ENODEV;
- cli = (void *)nvif_client(&chan->device->base);
+ cli = (void *)chan->user.client;
s = kzalloc(sizeof(*s), GFP_KERNEL);
if (!s)
@@ -815,7 +829,6 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
struct drm_device *dev = drm->dev;
struct nouveau_page_flip_state *s;
unsigned long flags;
- int crtcid = -1;
spin_lock_irqsave(&dev->event_lock, flags);
@@ -827,15 +840,19 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
if (s->event) {
- /* Vblank timestamps/counts are only correct on >= NV-50 */
- if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
- crtcid = s->crtc;
+ if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) {
+ drm_arm_vblank_event(dev, s->crtc, s->event);
+ } else {
+ drm_send_vblank_event(dev, s->crtc, s->event);
- drm_send_vblank_event(dev, crtcid, s->event);
+ /* Give up ownership of vblank for page-flipped crtc */
+ drm_vblank_put(dev, s->crtc);
+ }
+ }
+ else {
+ /* Give up ownership of vblank for page-flipped crtc */
+ drm_vblank_put(dev, s->crtc);
}
-
- /* Give up ownership of vblank for page-flipped crtc */
- drm_vblank_put(dev, s->crtc);
list_del(&s->head);
if (ps)
@@ -847,10 +864,10 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
}
int
-nouveau_flip_complete(void *data)
+nouveau_flip_complete(struct nvif_notify *notify)
{
- struct nouveau_channel *chan = data;
- struct nouveau_drm *drm = chan->drm;
+ struct nouveau_drm *drm = container_of(notify, typeof(*drm), flip);
+ struct nouveau_channel *chan = drm->channel;
struct nouveau_page_flip_state state;
if (!nouveau_finish_page_flip(chan, &state)) {
@@ -861,7 +878,7 @@ nouveau_flip_complete(void *data)
}
}
- return 0;
+ return NVIF_NOTIFY_KEEP;
}
int