From patchwork Thu Jun 6 20:20:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: James Hilliard X-Patchwork-Id: 10980449 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C99011515 for ; Thu, 6 Jun 2019 20:20:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B7F56205A4 for ; Thu, 6 Jun 2019 20:20:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AC26728AB6; Thu, 6 Jun 2019 20:20:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 89B59205A4 for ; Thu, 6 Jun 2019 20:20:58 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B4BBA89812; Thu, 6 Jun 2019 20:20:56 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-it1-x142.google.com (mail-it1-x142.google.com [IPv6:2607:f8b0:4864:20::142]) by gabe.freedesktop.org (Postfix) with ESMTPS id 1001989812 for ; Thu, 6 Jun 2019 20:20:56 +0000 (UTC) Received: by mail-it1-x142.google.com with SMTP id j204so2017697ite.4 for ; Thu, 06 Jun 2019 13:20:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=sUXm3Wd8oYuxkA69NiXfIS+UrWdJqjnOIx5pX1NZf1s=; b=ftPvcGeSUbV2iO3dv1serfELIt97FnriN6WsgkkIQZqnkJ3w3hhVkEZq3yTcZXa63F dlIiWGu5ytKQjQo3FxFP7OwHolh8CkYsYptDgZvpMpBdXfJX6QKEoQYYl1POLBSO8kf0 /KXJA7BLghbAlxiKcpHLOLqErI3jvoAXPWpkp9td9AjXOeKH03E7JUHtHnWScVv2Wz3e pnbXtDSH4/Pfzq8jFtdr/8Qlu4av6NmykEUhbBjVPs0Pf0+WPdRKDt7vZ1hsrXGNlH+9 xD5JHpfieYSt+1oHdF6BhAFdTuhEOz9eqgraMo33nkKYz/jIrjroqwfgmkJeU5uMLuuv e+sw== X-Gm-Message-State: APjAAAXtqEa/QWn1BFcvly5Qxp7XX1JfS2J51DWOsnB25/9JB5yXmyJC m6D69QxzdEl9KNSXcCwtLe5Ibats+WQ= X-Google-Smtp-Source: APXvYqxLf4ImG3HIcS6elCvmAEy24g+oFz5LYUgolsrgmpcFEUUiPhlxihcEYwTjp0bJnL6pv8MYcA== X-Received: by 2002:a24:9083:: with SMTP id x125mr1633343itd.76.1559852454641; Thu, 06 Jun 2019 13:20:54 -0700 (PDT) Received: from james-x399.Home (97-118-163-58.hlrn.qwest.net. [97.118.163.58]) by smtp.gmail.com with ESMTPSA id v130sm1318384itc.8.2019.06.06.13.20.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 06 Jun 2019 13:20:53 -0700 (PDT) From: James Hilliard To: dri-devel@lists.freedesktop.org Subject: [RFC PATCH 1/1] drm/gma500: add atomic support Date: Thu, 6 Jun 2019 14:20:32 -0600 Message-Id: <20190606202032.29748-1-james.hilliard1@gmail.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=sUXm3Wd8oYuxkA69NiXfIS+UrWdJqjnOIx5pX1NZf1s=; b=CxyFdkUwUKg/DbpbS1JxSdEOxljQTmdE2c4TtgnVB0Lc8W44Qp9sMFoA4oE91ycRSp JCCAMKu30GzN3UTi6vRWAyXJjr9wscqY/MiBKyz6TdHtODkl+ynEtCQkstu/TR3LsLSR leJrntCLOhaNI4+FJ34Nu6W6IaM4HHEDmluiC+mE6dVooSkNQ+Lf2v1X7TqcZ5/VDhen ORN1Q5OGqwkpSciOQY8MzBw3yzvu/TSY+A9q8aqvL+LA5cSg1VR9xEYTzMSE8/5DNzs5 OiM5EMhugvJ/xzKNDJG0whIzwm+DVTd2JXPSQOIiKzrcr4vIvu0JXz9BUMd8QNUcDXgj xcgA== X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: James Hilliard Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP Imported from https://git.tizen.org/cgit/kernel/kernel-mfld-blackbay/ This is currently not functional and based off of an older version of the gma500 driver. From the commit log this was written by Intel, is anyone aware of a more up to date version? I'm looking to see if this would be a decent starting point for adding gma500 atomic support to mainline and how best to approach that. Signed-off-by: James Hilliard --- drivers/gpu/drm/gma500/Makefile | 1 + drivers/gpu/drm/gma500/psb_page_flip.c | 600 +++++++++++++++++++++++++ drivers/gpu/drm/gma500/psb_page_flip.h | 38 ++ 3 files changed, 639 insertions(+) create mode 100644 drivers/gpu/drm/gma500/psb_page_flip.c create mode 100644 drivers/gpu/drm/gma500/psb_page_flip.h diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile index c8f2c89be99d..3db535ef51cb 100644 --- a/drivers/gpu/drm/gma500/Makefile +++ b/drivers/gpu/drm/gma500/Makefile @@ -24,6 +24,7 @@ gma500_gfx-y += \ psb_intel_sdvo.o \ psb_lid.o \ psb_irq.o \ + psb_page_flip.o \ psb_device.o \ mid_bios.o diff --git a/drivers/gpu/drm/gma500/psb_page_flip.c b/drivers/gpu/drm/gma500/psb_page_flip.c new file mode 100644 index 000000000000..6a93727cf1c1 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_page_flip.c @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2011-2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc.,· + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Authors: + * Ander Conselvan de Oliveira + * Pauli Nieminen + * Ville Syrjälä + */ + +#include +#include + +#include +#include "psb_drv.h" +#include "framebuffer.h" +#include "psb_intel_reg.h" +#include "psb_page_flip.h" + +#include "mdfld_output.h" +#include "mdfld_dsi_output.h" + +#if defined(CONFIG_MDFLD_DUAL_DSI_DPU) +#include "mdfld_dsi_dbi_dpu.h" +#elif defined(CONFIG_MDFLD_DSI_DSR) +#include "mdfld_dsi_dbi.h" +#endif + +struct pending_flip { + struct drm_crtc *crtc; + struct drm_pending_vblank_event *event; + PVRSRV_KERNEL_MEM_INFO *mem_info; + PVRSRV_KERNEL_MEM_INFO *old_mem_info; + uint32_t offset; + struct list_head uncompleted; + struct pvr_pending_sync pending_sync; + struct drm_flip base; + u32 vbl_count; + struct list_head companions; + u32 tgid; + bool vblank_ref; + atomic_t refcnt; + struct psb_pending_values pending_values; +}; + +enum { + /* somwehat arbitrary value */ + PSB_VBL_CNT_TIMEOUT = 5, +}; + +static u32 get_vbl_count(struct drm_crtc *crtc) +{ + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + struct drm_psb_private *dev_priv = crtc->dev->dev_private; + int pipe = psb_intel_crtc->pipe; + u32 high, low1, low2, dsl; + unsigned int timeout = 0; + + /* All reads must be satisfied during the same frame */ + do { + void __iomem *reg_pixel; + void __iomem *reg_high; + + reg_pixel = dev_priv->vdc_reg + PSB_PIPEFRAMEPIXEL(pipe); + reg_high = dev_priv->vdc_reg + PSB_PIPEFRAMEHIGH(pipe); + low1 = ioread32(reg_pixel) >> PIPE_FRAME_LOW_SHIFT; + high = ioread32(reg_high) << 8; + dsl = ioread32(dev_priv->vdc_reg + PSB_PIPE_DSL(pipe)); + low2 = ioread32(reg_pixel) >> PIPE_FRAME_LOW_SHIFT; + } while (low1 != low2 && timeout++ < PSB_VBL_CNT_TIMEOUT); + + if (timeout >= PSB_VBL_CNT_TIMEOUT) + dev_warn(crtc->dev->dev, + "Timed out while determining VBL count for pipe %d\n", + psb_intel_crtc->pipe); + + /* + * The frame counter seems to increment at the beginning of the + * last scanline. The hardware performs the flip at the start + * of the vblank, so we want to count those events instead. + * Cook up a vblank counter from the frame counter and scanline + * counter. + */ + return ((high | low2) + + ((dsl >= crtc->hwmode.crtc_vdisplay) && + (dsl < crtc->hwmode.crtc_vtotal - 1))) & 0xffffff; +} + +static unsigned int usecs_to_scanlines(struct drm_crtc *crtc, + unsigned int usecs) +{ + /* paranoia */ + if (!crtc->hwmode.crtc_htotal) + return 1; + + return DIV_ROUND_UP(usecs * crtc->hwmode.clock, + 1000 * crtc->hwmode.crtc_htotal); +} + +/* Called with interrupts off. */ +static void avoid_danger_zone(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + /* + * With CRTC and one overlay we're usually spending 30-40 usecs + * between avoid_danger_zone() and psb_flip_driver_flush(). Leave + * a small safety margin and avoid flipping while under 60 usec + * from the vblank start. + */ + u32 min = crtc->hwmode.crtc_vdisplay - usecs_to_scanlines(crtc, 60); + u32 max = crtc->hwmode.crtc_vdisplay - 1; + long timeout = msecs_to_jiffies(1); + u32 val; + + drm_vblank_get(dev, pipe); + + psb_intel_crtc->vbl_received = false; + val = ioread32(dev_priv->vdc_reg + PSB_PIPE_DSL(pipe)); + + while (val >= min && val <= max && timeout > 0) { + local_irq_enable(); + + timeout = wait_event_timeout(psb_intel_crtc->vbl_wait, + psb_intel_crtc->vbl_received, + timeout); + + local_irq_disable(); + + psb_intel_crtc->vbl_received = false; + val = ioread32(dev_priv->vdc_reg + PSB_PIPE_DSL(pipe)); + } + + drm_vblank_put(dev, pipe); + + if (val >= min && val <= max) + dev_warn(dev->dev, + "Page flipping close to vblank start (DSL=%u, VBL=%u)\n", + val, crtc->hwmode.crtc_vdisplay); +} + +void +psb_cleanup_pending_events(struct drm_device *dev, struct psb_fpriv *priv) +{ + struct drm_pending_vblank_event *e; + struct pending_flip *pending_flip, *temp; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + list_for_each_entry_safe(pending_flip, temp, &priv->pending_flips, + uncompleted) { + e = pending_flip->event; + pending_flip->event = NULL; + e->base.destroy(&e->base); + list_del_init(&pending_flip->uncompleted); + } + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +static void +send_page_flip_event(struct drm_device *dev, int pipe, + struct pending_flip *pending_flip) +{ + struct drm_pending_vblank_event *e; + struct timeval now; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + + if (!pending_flip->event) + goto unlock; + + list_del(&pending_flip->uncompleted); + e = pending_flip->event; + do_gettimeofday(&now); + e->event.sequence = drm_vblank_count(dev, pipe); + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + list_add_tail(&e->base.link, + &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + +unlock: + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +static void free_flip(struct pending_flip *crtc_flip) +{ + if (atomic_dec_and_test(&crtc_flip->refcnt)) { + psb_fb_unref(crtc_flip->old_mem_info, crtc_flip->tgid); + kfree(crtc_flip); + } +} + +static void crtc_flip_cleanup(struct drm_flip *flip) +{ + struct pending_flip *crtc_flip = + container_of(flip, struct pending_flip, base); + struct drm_device *dev = crtc_flip->crtc->dev; + + mutex_lock(&dev->mode_config.mutex); + psb_fb_gtt_unref(dev, crtc_flip->mem_info, crtc_flip->tgid); + mutex_unlock(&dev->mode_config.mutex); + + free_flip(crtc_flip); +} + +static void crtc_flip_finish(struct drm_flip *flip) +{ +} + +static void psb_flip_driver_flush(struct drm_flip_driver *driver) +{ + struct drm_psb_private *dev_priv = + container_of(driver, struct drm_psb_private, flip_driver); + + /* Flush posted writes */ + (void)ioread32(dev_priv->vdc_reg + PSB_PIPESTAT(PSB_PIPE_A)); +} + +static void psb_flip_complete_sync_callback(struct pvr_pending_sync *sync, + bool call_from_work) +{ + struct pending_flip *crtc_flip = + container_of(sync, struct pending_flip, pending_sync); + + if (psb_fb_increase_read_ops_completed(crtc_flip->old_mem_info, + &crtc_flip->pending_values, sync)) { + WARN(true, "Sync callback called without completing operation"); + return; + } + + free_flip(crtc_flip); + + if (call_from_work) + mutex_lock(&gPVRSRVLock); + + PVRSRVScheduleDeviceCallbacks(); + + if (call_from_work) + mutex_unlock(&gPVRSRVLock); +} + +static void crtc_flip_complete(struct drm_flip *flip) +{ + struct pending_flip *crtc_flip = + container_of(flip, struct pending_flip, base); + struct drm_device *dev = crtc_flip->crtc->dev; + int pipe = to_psb_intel_crtc(crtc_flip->crtc)->pipe; + + send_page_flip_event(dev, pipe, crtc_flip); + + if (crtc_flip->vblank_ref) + drm_vblank_put(dev, pipe); + + atomic_inc(&crtc_flip->refcnt); + crtc_flip->pending_sync.callback = psb_flip_complete_sync_callback; + if (psb_fb_increase_read_ops_completed(crtc_flip->old_mem_info, + &crtc_flip->pending_values, + &crtc_flip->pending_sync)) + return; + + free_flip(crtc_flip); + PVRSRVScheduleDeviceCallbacks(); +} + +static const struct drm_flip_driver_funcs psb_flip_driver_funcs = { + .flush = psb_flip_driver_flush, +}; + +void psb_page_flip_init(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + drm_flip_driver_init(&dev_priv->flip_driver, + &psb_flip_driver_funcs); +} + +void psb_page_flip_fini(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + drm_flip_driver_fini(&dev_priv->flip_driver); +} + +static bool vbl_count_after_eq(u32 a, u32 b) +{ + return !((a - b) & 0x800000); +} + +static bool crtc_check(struct drm_flip *pending_flip, + u32 vbl_count) +{ + struct pending_flip *crtc_flip = + container_of(pending_flip, struct pending_flip, base); + + return vbl_count_after_eq(vbl_count, crtc_flip->vbl_count); +} + +static bool crtc_flip(struct drm_flip *flip, + struct drm_flip *pending_flip) +{ + struct pending_flip *crtc_flip = container_of(flip, struct pending_flip, base); + struct drm_crtc *crtc = crtc_flip->crtc; + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + int pipe = to_psb_intel_crtc(crtc)->pipe; + u32 vbl_count; + + crtc_flip->vblank_ref = drm_vblank_get(dev, pipe) == 0; + + vbl_count = get_vbl_count(crtc); + + iowrite32(crtc_flip->offset, dev_priv->vdc_reg + PSB_DSPSURF(pipe)); + + /* This flip will happen on the next vblank */ + crtc_flip->vbl_count = (vbl_count + 1) & 0xffffff; + + if (pending_flip) { + struct pending_flip *old_crtc_flip = + container_of(pending_flip, struct pending_flip, base); + bool flipped = crtc_check(pending_flip, vbl_count); + + if (!flipped) { + swap(crtc_flip->old_mem_info, old_crtc_flip->old_mem_info); + swap(crtc_flip->pending_values, old_crtc_flip->pending_values); + } + + return flipped; + } + + return false; +} + +static bool crtc_vblank(struct drm_flip *pending_flip) +{ + struct pending_flip *crtc_flip = + container_of(pending_flip, struct pending_flip, base); + u32 vbl_count = get_vbl_count(crtc_flip->crtc); + + return crtc_check(pending_flip, vbl_count); +} + +static const struct drm_flip_helper_funcs crtc_flip_funcs = { + .flip = crtc_flip, + .vblank = crtc_vblank, + .complete = crtc_flip_complete, + .finish = crtc_flip_finish, + .cleanup = crtc_flip_cleanup, +}; + +void psb_page_flip_crtc_init(struct psb_intel_crtc *psb_intel_crtc) +{ + struct drm_device *dev = psb_intel_crtc->base.dev; + struct drm_psb_private *dev_priv = dev->dev_private; + + drm_flip_helper_init(&psb_intel_crtc->flip_helper, + &dev_priv->flip_driver, + &crtc_flip_funcs); +} + +void psb_page_flip_crtc_fini(struct psb_intel_crtc *psb_intel_crtc) +{ + drm_flip_helper_fini(&psb_intel_crtc->flip_helper); +} + +static void +psb_intel_crtc_process_vblank_real(struct drm_crtc *crtc) +{ + struct drm_psb_private *dev_priv = crtc->dev->dev_private; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + int i; + + psb_intel_crtc->vbl_received = true; + wake_up(&psb_intel_crtc->vbl_wait); + + for (i = 0; i < ARRAY_SIZE(dev_priv->overlays); i++) { + if (!dev_priv->overlays[i]) + continue; + + mdfld_overlay_process_vblank(dev_priv->overlays[i], pipe); + } + + drm_flip_helper_vblank(&psb_intel_crtc->flip_helper); +} + +void +psb_intel_crtc_process_vblank(struct drm_crtc *crtc) +{ + struct drm_psb_private *dev_priv = crtc->dev->dev_private; + struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc); + int pipe = psb_intel_crtc->pipe; + struct drm_connector *connector; + struct drm_crtc *hdmicrtc = NULL; + + psb_intel_crtc_process_vblank_real(crtc); + + /* This following is to handle HDMI pending flips if unplug the cable + * After HDMI is unpluged, there is no vblank interrupt anymore. + * But there may be some pending flips exists in psb_intel_crtc. + * We need complet the pending flips. + * This can be REVERTED, if the pending flip issue fixed. + */ + if (pipe != 0) + return; + + hdmicrtc = dev_priv->pipe_to_crtc_mapping[1]; + if (!hdmicrtc) + return; + + list_for_each_entry(connector, + &crtc->dev->mode_config.connector_list, head) { + if (connector->connector_type == DRM_MODE_CONNECTOR_DVID && + connector->status == connector_status_disconnected) { + psb_intel_crtc_process_vblank_real(hdmicrtc); + break; + } + } +} + +static void +sync_callback(struct pvr_pending_sync *pending_sync, bool from_misr) +{ + struct pending_flip *pending_flip = + container_of(pending_sync, struct pending_flip, pending_sync); + struct drm_crtc* crtc = pending_flip->crtc; + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct drm_flip *flip, *next; + LIST_HEAD(flips); + bool pipe_enabled = false; + + list_add_tail(&pending_flip->base.list, &flips); + + list_for_each_entry_safe(flip, next, &pending_flip->companions, list) + list_move_tail(&flip->list, &flips); + + WARN_ON(!list_empty(&pending_flip->companions)); + + /* prevent DPMS and whatnot from shooting us in the foot */ + if (from_misr) + mutex_lock(&dev->mode_config.mutex); + + if (ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND, false)) { + int pipe = to_psb_intel_crtc(crtc)->pipe; + u32 val; + + val = ioread32(dev_priv->vdc_reg + PSB_PIPECONF(pipe)); + + pipe_enabled = val & PIPEACONF_ENABLE; + + if (!pipe_enabled) + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); + } + + if (pipe_enabled) { + drm_flip_driver_prepare_flips(&dev_priv->flip_driver, &flips); + + /* Make sure we're not interrupted during the critical phase */ + local_irq_disable(); + + /* + * If we cross into vblank while programming the flips, we + * can't determine which flips have completed. Also when + * trying to synchronize multiple flips, we can't be sure + * that all flips will happen on the same vblank. So, if + * we're close to the start of vblank, wait until we're + * safely past it before proceeding any further. + */ + avoid_danger_zone(crtc); + + drm_flip_driver_schedule_flips(&dev_priv->flip_driver, &flips); + + local_irq_enable(); + + ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND); + } else + /* powered off, just complete all pending and new flips */ + drm_flip_driver_complete_flips(&dev_priv->flip_driver, &flips); + + if (from_misr) + mutex_unlock(&dev->mode_config.mutex); +} + +int +psb_intel_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct drm_device *dev = crtc->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + struct psb_framebuffer *psbfb = to_psb_fb(fb); + PVRSRV_KERNEL_MEM_INFO *current_fb_mem_info; + struct pending_flip *new_pending_flip; + struct psb_fpriv *priv; + struct psb_fbdev *fbdev = NULL; + unsigned long flags; + u32 tgid = psb_get_tgid(); + int ret; + int pipe = to_psb_intel_crtc(crtc)->pipe; + int i; + + if (!psbfb->pvrBO) + return -EINVAL; + + new_pending_flip = kzalloc(sizeof *new_pending_flip, GFP_KERNEL); + if (!new_pending_flip) + return -ENOMEM; + + /* keep a reference to the new fb, until it's no longer scanned out. */ + ret = psb_fb_gtt_ref(dev, psbfb->pvrBO); + if (ret) { + kfree(new_pending_flip); + return ret; + } + + current_fb_mem_info = to_psb_fb(crtc->fb)->pvrBO; + + /* keep a reference to the old fb, for read ops manipulations */ + ret = psb_fb_ref(current_fb_mem_info); + if (ret) { + psb_fb_gtt_unref(dev, psbfb->pvrBO, tgid); + kfree(new_pending_flip); + return ret; + } + + drm_flip_init(&new_pending_flip->base, &to_psb_intel_crtc(crtc)->flip_helper); + + atomic_set(&new_pending_flip->refcnt, 1); + new_pending_flip->crtc = crtc; + new_pending_flip->event = event; + new_pending_flip->offset = psbfb->offset; + + if (event) { + spin_lock_irqsave(&crtc->dev->event_lock, flags); + priv = psb_fpriv(event->base.file_priv); + list_add(&new_pending_flip->uncompleted, &priv->pending_flips); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + } else { + INIT_LIST_HEAD(&new_pending_flip->uncompleted); + } + + /* In page flip, change the psb_fb_helper.fb + * and fbdev to the swapped fb. + */ + if (dev->dev_private) + fbdev = ((struct drm_psb_private *)dev->dev_private)->fbdev; + if (fbdev) { + fbdev->psb_fb_helper.fb = fb; + fbdev->psb_fb_helper.fbdev = psbfb->fbdev; + } else + printk(KERN_ALERT "%s cannot find the fb\n", __func__); + + crtc->fb = fb; + + new_pending_flip->mem_info = psbfb->pvrBO; + new_pending_flip->old_mem_info = current_fb_mem_info; + + psb_fb_increase_read_ops_pending(current_fb_mem_info, + &new_pending_flip->pending_values); + psb_fb_flip_trace(current_fb_mem_info, psbfb->pvrBO); + + new_pending_flip->tgid = tgid; + + INIT_LIST_HEAD(&new_pending_flip->companions); + + for (i = 0; i < ARRAY_SIZE(dev_priv->overlays); i++) { + struct drm_flip *flip; + + if (!dev_priv->overlays[i]) + continue; + + flip = mdfld_overlay_atomic_flip(dev_priv->overlays[i], pipe); + if (!flip) + continue; + + list_add_tail(&flip->list, &new_pending_flip->companions); + } + + PVRSRVCallbackOnSync(psbfb->pvrBO->psKernelSyncInfo, + PVRSRV_SYNC_WRITE, sync_callback, + &new_pending_flip->pending_sync); + + return 0; +} diff --git a/drivers/gpu/drm/gma500/psb_page_flip.h b/drivers/gpu/drm/gma500/psb_page_flip.h new file mode 100644 index 000000000000..60671201d2c8 --- /dev/null +++ b/drivers/gpu/drm/gma500/psb_page_flip.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc.,· + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * Authors: + * Ander Conselvan de Oliveira + * + */ + +#ifndef _PSB_PAGE_FLIP_H_ +#define _PSB_PAGE_FLIP_H_ + +void psb_page_flip_init(struct drm_device *dev); +void psb_page_flip_fini(struct drm_device *dev); + +void psb_page_flip_crtc_init(struct psb_intel_crtc *psb_intel_crtc); +void psb_page_flip_crtc_fini(struct psb_intel_crtc *psb_intel_crtc); + +void psb_intel_crtc_process_vblank(struct drm_crtc *crtc); +int psb_intel_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event); +void psb_cleanup_pending_events(struct drm_device *dev, + struct psb_fpriv *priv); + +#endif /* _PSB_PAGE_FLIP_H_ */