From patchwork Mon Sep 9 14:06:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11138059 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E9C7414DB for ; Mon, 9 Sep 2019 14:06:46 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D1A4A218DE for ; Mon, 9 Sep 2019 14:06:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D1A4A218DE Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 163F889C80; Mon, 9 Sep 2019 14:06:44 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mx1.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id DFBB589C86 for ; Mon, 9 Sep 2019 14:06:37 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 4557CACC9; Mon, 9 Sep 2019 14:06:36 +0000 (UTC) From: Thomas Zimmermann To: daniel@ffwll.ch, airlied@redhat.com, noralf@tronnes.org, rong.a.chen@intel.com, feng.tang@intel.com, ying.huang@intel.com Subject: [PATCH 2/2] drm/mgag200: Add vblank support Date: Mon, 9 Sep 2019 16:06:33 +0200 Message-Id: <20190909140633.31260-3-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20190909140633.31260-1-tzimmermann@suse.de> References: <20190909140633.31260-1-tzimmermann@suse.de> MIME-Version: 1.0 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: Thomas Zimmermann , dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Support for vblank requires VSYNC to signal an interrupt, which is broken on Matrox chipsets. The workaround that is used here and in other free Matrox drivers is to program to the value of and enable the VLINE interrupt. This triggers an interrupt at the same time when VSYNC begins. VLINE uses separate registers for enabling and clearing pending interrupts. No extra syncronization between irq handler and the rest of the driver is required. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/mgag200/mgag200_drv.c | 1 + drivers/gpu/drm/mgag200/mgag200_drv.h | 1 + drivers/gpu/drm/mgag200/mgag200_main.c | 33 ++++++++++++++++++++ drivers/gpu/drm/mgag200/mgag200_mode.c | 42 +++++++++++++++++++++++--- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 4f9df3b93598..cff265973154 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -67,6 +67,7 @@ static struct drm_driver driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET, .load = mgag200_driver_load, .unload = mgag200_driver_unload, + .irq_handler = mgag200_irq_handler, .fops = &mgag200_driver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 1c93f8dc08c7..88cf256d135f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -195,6 +195,7 @@ void mgag200_modeset_fini(struct mga_device *mdev); /* mgag200_main.c */ int mgag200_driver_load(struct drm_device *dev, unsigned long flags); void mgag200_driver_unload(struct drm_device *dev); +irqreturn_t mgag200_irq_handler(int irq, void *arg); /* mgag200_i2c.c */ struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev); diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index a9773334dedf..5941607796e8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -10,7 +10,9 @@ #include #include +#include #include +#include #include "mgag200_drv.h" @@ -186,10 +188,18 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags) } mdev->cursor.pixels_current = NULL; + r = drm_vblank_init(dev, 1); + if (r) + goto err_modeset; + r = drm_fbdev_generic_setup(mdev->dev, 0); if (r) goto err_modeset; + r = drm_irq_install(dev, dev->pdev->irq); + if (r) + goto err_modeset; + return 0; err_modeset: @@ -207,8 +217,31 @@ void mgag200_driver_unload(struct drm_device *dev) if (mdev == NULL) return; + drm_irq_uninstall(dev); mgag200_modeset_fini(mdev); drm_mode_config_cleanup(dev); mgag200_mm_fini(mdev); dev->dev_private = NULL; } + +irqreturn_t mgag200_irq_handler(int irq, void *arg) +{ + struct drm_device *dev = arg; + struct mga_device *mdev = dev->dev_private; + struct drm_crtc *crtc; + u32 status, iclear; + + status = RREG32(0x1e14); + + if (status & 0x00000020) { /* test */ + drm_for_each_crtc(crtc, dev) { + drm_crtc_handle_vblank(crtc); + } + iclear = RREG32(0x1e18); + iclear |= 0x00000020; /* set */ + WREG32(0x1e18, iclear); + return IRQ_HANDLED; + } + + return IRQ_NONE; +}; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 5e778b5f1a10..ffe5f15d0a7d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -905,6 +905,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, const struct drm_framebuffer *fb = crtc->primary->fb; int hdisplay, hsyncstart, hsyncend, htotal; int vdisplay, vsyncstart, vsyncend, vtotal; + int linecomp; int pitch; int option = 0, option2 = 0; int i; @@ -1042,6 +1043,13 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, vsyncend = mode->vsync_end - 1; vtotal = mode->vtotal - 2; + /* The VSYNC interrupt is broken on Matrox chipsets. We use + * the VLINE interrupt instead. It triggers when the current + * linecomp has been reached. Therefore keep in + * sync with . + */ + linecomp = vdisplay; + WREG_GFX(0, 0); WREG_GFX(1, 0); WREG_GFX(2, 0); @@ -1063,12 +1071,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, ((vdisplay & 0x100) >> 7) | ((vsyncstart & 0x100) >> 6) | ((vdisplay & 0x100) >> 5) | - ((vdisplay & 0x100) >> 4) | /* linecomp */ + ((linecomp & 0x100) >> 4) | ((vtotal & 0x200) >> 4)| ((vdisplay & 0x200) >> 3) | ((vsyncstart & 0x200) >> 2)); WREG_CRT(9, ((vdisplay & 0x200) >> 4) | - ((vdisplay & 0x200) >> 3)); + ((linecomp & 0x200) >> 3)); WREG_CRT(10, 0); WREG_CRT(11, 0); WREG_CRT(12, 0); @@ -1083,7 +1091,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, WREG_CRT(21, vdisplay & 0xFF); WREG_CRT(22, (vtotal + 1) & 0xFF); WREG_CRT(23, 0xc3); - WREG_CRT(24, vdisplay & 0xFF); + WREG_CRT(24, linecomp & 0xff); ext_vga[0] = 0; ext_vga[5] = 0; @@ -1099,7 +1107,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, ((vdisplay & 0x400) >> 8) | ((vdisplay & 0xc00) >> 7) | ((vsyncstart & 0xc00) >> 5) | - ((vdisplay & 0x400) >> 3); + ((linecomp & 0x400) >> 3); if (fb->format->cpp[0] * 8 == 24) ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80; else @@ -1411,6 +1419,30 @@ static void mga_crtc_disable(struct drm_crtc *crtc) crtc->primary->fb = NULL; } +static int mga_crtc_enable_vblank(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = dev->dev_private; + u32 ien; + + ien = RREG32(0x1e1c); + ien |= 0x00000020; /* set */ + WREG32(0x1e1c, ien); + + return 0; +} + +static void mga_crtc_disable_vblank(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct mga_device *mdev = dev->dev_private; + u32 ien; + + ien = RREG32(0x1e1c); + ien &= 0xffffffdf; /* clear */ + WREG32(0x1e1c, ien); +} + /* These provide the minimum set of functions required to handle a CRTC */ static const struct drm_crtc_funcs mga_crtc_funcs = { .cursor_set = mga_crtc_cursor_set, @@ -1418,6 +1450,8 @@ static const struct drm_crtc_funcs mga_crtc_funcs = { .gamma_set = mga_crtc_gamma_set, .set_config = drm_crtc_helper_set_config, .destroy = mga_crtc_destroy, + .enable_vblank = mga_crtc_enable_vblank, + .disable_vblank = mga_crtc_disable_vblank, }; static const struct drm_crtc_helper_funcs mga_helper_funcs = {