From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932692AbcGLKUi (ORCPT ); Tue, 12 Jul 2016 06:20:38 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:35500 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751374AbcGLKUh (ORCPT ); Tue, 12 Jul 2016 06:20:37 -0400 Date: Tue, 12 Jul 2016 12:20:32 +0200 From: Daniel Vetter To: Andrea Merello Cc: dri-devel@lists.freedesktop.org, David Airlie , Claudio Lorini , linux-kernel , Stefan Kristiansson , Tomi Valkeinen , Francesco Diotalevi Subject: Re: [PATCH 1/2] drm: Add drm driver for OpenCores VGA/LCD display controller Message-ID: <20160712102032.GX23520@phenom.ffwll.local> Mail-Followup-To: Andrea Merello , dri-devel@lists.freedesktop.org, David Airlie , Claudio Lorini , linux-kernel , Stefan Kristiansson , Tomi Valkeinen , Francesco Diotalevi References: <1465479175-9713-1-git-send-email-andrea.merello@gmail.com> <20160610142729.GC3363@phenom.ffwll.local> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: X-Operating-System: Linux phenom 4.6.0-rc5+ User-Agent: Mutt/1.6.0 (2016-04-01) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, Jun 27, 2016 at 01:33:24PM +0200, Andrea Merello wrote: > On Fri, Jun 10, 2016 at 4:27 PM, Daniel Vetter wrote: > > On Thu, Jun 09, 2016 at 03:32:55PM +0200, Andrea Merello wrote: > >> This driver supports the VGA/LCD core available from OpenCores: > >> http://opencores.org/project,vga_lcd > >> > >> It's intended as a replacement for the "ocfb" framebuffer driver > >> > >> Signed-off-by: Andrea Merello > >> Cc: Stefan Kristiansson > >> Cc: Tomi Valkeinen > >> Cc: Francesco Diotalevi > >> Cc: Claudio Lorini > > > > Bunch of comments below, but this driver might be a good candidate for the > > drm_simple_display_pipe helpers that Noralf Tronnes is working on. Would > > allow you to cut down a pile more boilerplate I think. Please take a look. > > I think the only thing you'd need is a new small function to set the > > drm_bridge for the encoder in struct drm_simple_display_pipe > > Yes, it seems a good option. I'll look into it. > > Beside this, OK for all your comments below. > > BTW I forgot to mention that, beside we are using it with a HDMI > bridge, it would need something like the "RGB to VGA bridge" patch > from Maxime Ripard [1] to actually replace the old "ocfb" driver. Is > it likely to be accepted for merge sooner or later ? > > [1] https://patchwork.kernel.org/patch/9102271/ Sure, just needs review/testing and then it can be merged. But 4.8 is getting awefully close (drm subsystem starts closing down after -rc5), so probably 4.9 material all. -Daniel > > > > -Daniel > > > >> --- > >> drivers/gpu/drm/Kconfig | 2 + > >> drivers/gpu/drm/Makefile | 1 + > >> drivers/gpu/drm/ocdrm/Kconfig | 7 + > >> drivers/gpu/drm/ocdrm/Makefile | 7 + > >> drivers/gpu/drm/ocdrm/ocdrm_crtc.c | 336 ++++++++++++++++++++++++++++++++++ > >> drivers/gpu/drm/ocdrm/ocdrm_crtc.h | 48 +++++ > >> drivers/gpu/drm/ocdrm/ocdrm_drv.c | 312 +++++++++++++++++++++++++++++++ > >> drivers/gpu/drm/ocdrm/ocdrm_drv.h | 89 +++++++++ > >> drivers/gpu/drm/ocdrm/ocdrm_encoder.c | 95 ++++++++++ > >> drivers/gpu/drm/ocdrm/ocdrm_encoder.h | 48 +++++ > >> 10 files changed, 945 insertions(+) > >> create mode 100644 drivers/gpu/drm/ocdrm/Kconfig > >> create mode 100644 drivers/gpu/drm/ocdrm/Makefile > >> create mode 100644 drivers/gpu/drm/ocdrm/ocdrm_crtc.c > >> create mode 100644 drivers/gpu/drm/ocdrm/ocdrm_crtc.h > >> create mode 100644 drivers/gpu/drm/ocdrm/ocdrm_drv.c > >> create mode 100644 drivers/gpu/drm/ocdrm/ocdrm_drv.h > >> create mode 100644 drivers/gpu/drm/ocdrm/ocdrm_encoder.c > >> create mode 100644 drivers/gpu/drm/ocdrm/ocdrm_encoder.h > >> > >> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig > >> index fc35731..48f56e4 100644 > >> --- a/drivers/gpu/drm/Kconfig > >> +++ b/drivers/gpu/drm/Kconfig > >> @@ -290,3 +290,5 @@ source "drivers/gpu/drm/arc/Kconfig" > >> source "drivers/gpu/drm/hisilicon/Kconfig" > >> > >> source "drivers/gpu/drm/mediatek/Kconfig" > >> + > >> +source "drivers/gpu/drm/ocdrm/Kconfig" > >> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile > >> index be43afb..871da6a 100644 > >> --- a/drivers/gpu/drm/Makefile > >> +++ b/drivers/gpu/drm/Makefile > >> @@ -82,3 +82,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ > >> obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ > >> obj-$(CONFIG_DRM_ARCPGU)+= arc/ > >> obj-y += hisilicon/ > >> +obj-$(CONFIG_DRM_OCDRM) += ocdrm/ > >> diff --git a/drivers/gpu/drm/ocdrm/Kconfig b/drivers/gpu/drm/ocdrm/Kconfig > >> new file mode 100644 > >> index 0000000..a918503 > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/Kconfig > >> @@ -0,0 +1,7 @@ > >> +config DRM_OCDRM > >> + tristate "DRM Support for opencores OCFB" > >> + depends on DRM > >> + default n > >> + select DRM_KMS_HELPER > >> + select DRM_KMS_CMA_HELPER > >> + select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE > >> diff --git a/drivers/gpu/drm/ocdrm/Makefile b/drivers/gpu/drm/ocdrm/Makefile > >> new file mode 100644 > >> index 0000000..4ea17d2 > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/Makefile > >> @@ -0,0 +1,7 @@ > >> +# > >> +# Makefile for the drm device driver. This driver provides support for the > >> +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. > >> + > >> +ocdrm-y := ocdrm_crtc.o ocdrm_drv.o ocdrm_encoder.o > >> + > >> +obj-$(CONFIG_DRM_OCDRM) += ocdrm.o > >> diff --git a/drivers/gpu/drm/ocdrm/ocdrm_crtc.c b/drivers/gpu/drm/ocdrm/ocdrm_crtc.c > >> new file mode 100644 > >> index 0000000..ebfe03e > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/ocdrm_crtc.c > >> @@ -0,0 +1,336 @@ > >> +/* > >> + * Open cores VGA/LCD 2.0 core DRM driver > >> + * Copyright (c) 2016 Istituto Italiano di Tecnologia > >> + * Electronic Design Lab. > >> + * > >> + * Author: Andrea Merello > >> + * > >> + * Based on the following drivers: > >> + * - Analog Devices AXI HDMI DRM driver, which is > >> + * Copyright 2012 Analog Devices Inc. > >> + * > >> + * - ARC PGU DRM driver. > >> + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) > >> + * > >> + * - ARM HDLCD Driver > >> + * Copyright (C) 2013-2015 ARM Limited > >> + * > >> + * - Atmel atmel-hlcdc driver, which is > >> + * Copyright (C) 2014 Traphandler > >> + * Copyright (C) 2014 Free Electrons > >> + * > >> + * - OpenCores VGA/LCD 2.0 core frame buffer driver > >> + * Copyright (C) 2013 Stefan Kristiansson, stefan.kristiansson@saunalahti.fi > >> + * > >> + * - R-Car Display Unit DRM driver > >> + * Copyright (C) 2013-2015 Renesas Electronics Corporation > >> + * > >> + * This program is free software; you can redistribute it and/or modify it > >> + * under the terms of the GNU General Public License version 2 as published by > >> + * the Free Software Foundation. > >> + * > >> + * This program is distributed in the hope that 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, see . > >> + */ > >> + > >> +#include > >> + > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> + > >> +#include "ocdrm_crtc.h" > >> + > >> + > >> +static inline struct ocdrm_priv *crtc_to_ocdrm(struct drm_crtc *crtc) > >> +{ > >> + return container_of(crtc, struct ocdrm_priv, crtc); > >> +} > >> + > >> +static inline struct ocdrm_priv *plane_to_ocdrm(struct drm_plane *plane) > >> +{ > >> + return container_of(plane, struct ocdrm_priv, plane); > >> +} > >> + > >> +static void ocdrm_plane_atomic_update(struct drm_plane *plane, > >> + struct drm_plane_state *old_state) > >> +{ > >> + struct drm_gem_cma_object *obj; > >> + u32 val; > >> + uint32_t pixel_format; > >> + int hgate; > >> + struct ocdrm_priv *priv = plane_to_ocdrm(plane); > >> + > >> + if (!plane->state->crtc || !plane->state->fb) > >> + return; > >> + > >> + pixel_format = plane->state->fb->pixel_format; > >> + hgate = plane->state->crtc->state->adjusted_mode.crtc_hdisplay; > >> + > >> + val = ocdrm_readreg(priv, OCFB_CTRL); > >> + ocdrm_writereg(priv, OCFB_CTRL, val & ~OCFB_CTRL_VEN); > >> + > >> + if (!drm_atomic_plane_disabling(plane, plane->state)) { > >> + obj = drm_fb_cma_get_gem_obj(plane->state->fb, 0); > >> + ocdrm_writereg(priv, OCFB_VBARA, obj->paddr); > >> + > >> + val &= ~(OCFB_CTRL_CD8 | OCFB_CTRL_CD16 | > >> + OCFB_CTRL_CD24 | OCFB_CTRL_CD32); > >> + val &= ~(OCFB_CTRL_VBL8 | OCFB_CTRL_VBL4 | > >> + OCFB_CTRL_VBL2 | OCFB_CTRL_VBL1); > >> + > >> + switch (pixel_format) { > >> + /* TODO > >> + *case DRM_FORMAT_RGB332: > >> + * hgate /= 4; > >> + * val |= OCFB_CTRL_CD8; > >> + * val |= OCFB_CTRL_PC; > >> + * break; > >> + */ > >> + > >> + case DRM_FORMAT_RGB565: > >> + dev_dbg(priv->drm_dev->dev, "16 bpp\n"); > >> + hgate /= 2; > >> + val |= OCFB_CTRL_CD16; > >> + break; > >> + > >> + case DRM_FORMAT_RGB888: > >> + dev_dbg(priv->drm_dev->dev, "24 bpp\n"); > >> + hgate = hgate * 3 / 4; > >> + val |= OCFB_CTRL_CD24; > >> + break; > >> + > >> + case DRM_FORMAT_XRGB8888: > >> + dev_dbg(priv->drm_dev->dev, "32 bpp\n"); > >> + val |= OCFB_CTRL_CD32; > >> + break; > >> + > >> + default: > >> + dev_err(priv->drm_dev->dev, "Invalid pixelformat specified\n"); > >> + return; > >> + } > >> + > >> + if ((0 == (obj->paddr & 0x1f)) && (0 == (hgate % 8))) { > >> + dev_dbg(priv->drm_dev->dev, "dma burst 8 cycles\n"); > >> + val |= OCFB_CTRL_VBL8; > >> + } else if ((0 == (obj->paddr & 0xf)) && (0 == (hgate % 4))) { > >> + dev_dbg(priv->drm_dev->dev, "dma burst 4 cycles\n"); > >> + val |= OCFB_CTRL_VBL4; > >> + } else if ((0 == (obj->paddr & 0x7)) && (0 == (hgate % 2))) { > >> + dev_dbg(priv->drm_dev->dev, "dma burst 2 cycles\n"); > >> + val |= OCFB_CTRL_VBL2; > >> + } else { > >> + dev_dbg(priv->drm_dev->dev, "dma burst 1 cycle\n"); > >> + val |= OCFB_CTRL_VBL1; > >> + } > >> + > >> + ocdrm_writereg(priv, OCFB_CTRL, val | OCFB_CTRL_VEN); > >> + } > >> +} > >> + > >> +static void ocdrm_crtc_enable(struct drm_crtc *crtc) > >> +{ > >> + > >> + struct ocdrm_priv *priv = crtc_to_ocdrm(crtc); > >> + > >> + if (!priv->clk_enabled) > >> + clk_prepare_enable(priv->pixel_clock); > >> + priv->clk_enabled = true; > >> +} > >> + > >> +static void ocdrm_crtc_disable(struct drm_crtc *crtc) > >> +{ > >> + struct ocdrm_priv *priv = crtc_to_ocdrm(crtc); > >> + > >> + /* why the plane has been not disabled ? .. we get here from destroy */ > >> + ocdrm_writereg(priv, OCFB_CTRL, 0); > >> + > >> + if (priv->clk_enabled) > >> + clk_disable_unprepare(priv->pixel_clock); > >> + priv->clk_enabled = false; > >> +} > >> + > >> +static void ocdrm_crtc_mode_set_nofb(struct drm_crtc *crtc) > >> +{ > >> + u32 ctrl; > >> + int ret; > >> + struct ocdrm_priv *priv = crtc_to_ocdrm(crtc); > >> + struct drm_display_mode *m = &crtc->state->adjusted_mode; > >> + uint32_t hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; > >> + uint32_t vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; > >> + uint32_t vback_porch = m->crtc_vtotal - m->crtc_vsync_end; > >> + uint32_t hback_porch = m->crtc_htotal - m->crtc_hsync_end; > >> + > >> + ctrl = ocdrm_readreg(priv, OCFB_CTRL); > >> + ocdrm_writereg(priv, OCFB_CTRL, ctrl & ~OCFB_CTRL_VEN); > >> + > >> + /* Horizontal timings */ > >> + ocdrm_writereg(priv, OCFB_HTIM, (hsync_len - 1) << 24 | > >> + (hback_porch - 1) << 16 | (m->crtc_hdisplay - 1)); > >> + > >> + /* Vertical timings */ > >> + ocdrm_writereg(priv, OCFB_VTIM, (vsync_len - 1) << 24 | > >> + (vback_porch - 1) << 16 | (m->crtc_vdisplay - 1)); > >> + > >> + ocdrm_writereg(priv, OCFB_HVLEN, ((uint32_t)m->crtc_htotal - 1) << 16 | > >> + (m->crtc_vtotal - 1)); > >> + > >> + dev_dbg(priv->drm_dev->dev, "set mode H slen %u, bporch %u, tot %u\n", > >> + hsync_len, hback_porch, m->crtc_htotal); > >> + dev_dbg(priv->drm_dev->dev, "set mode V slen %u, bporch %u, tot %u\n", > >> + vsync_len, vback_porch, m->crtc_vtotal); > >> + > >> + if (m->flags & DRM_MODE_FLAG_NHSYNC) > >> + ctrl |= OCFB_CTRL_HSL; > >> + else > >> + ctrl &= ~OCFB_CTRL_HSL; > >> + > >> + if (m->flags & DRM_MODE_FLAG_NVSYNC) > >> + ctrl |= OCFB_CTRL_VSL; > >> + else > >> + ctrl &= ~OCFB_CTRL_VSL; > >> + > >> + dev_dbg(priv->drm_dev->dev, "VPOL %d, HPOL %d\n", > >> + m->flags & DRM_MODE_FLAG_NVSYNC, > >> + m->flags & DRM_MODE_FLAG_NHSYNC); > >> + > >> + > >> + /* Set sync polarity. */ > >> + ocdrm_writereg(priv, OCFB_CTRL, ctrl); > >> + > >> + if (priv->clk_enabled) > >> + clk_disable_unprepare(priv->pixel_clock); > >> + > >> + ret = clk_set_rate(priv->pixel_clock, m->crtc_clock * 1000); > >> + if (ret) { > >> + dev_err(priv->drm_dev->dev, "failed to set pixclk %d\n", ret); > >> + return; > >> + } > >> + > >> + if (priv->clk_enabled) > >> + clk_prepare_enable(priv->pixel_clock); > >> + > >> + dev_dbg(priv->drm_dev->dev, "pixel clock: %d\n", m->crtc_clock); > >> + > >> + /* if video was enabled, then enable it */ > >> + ocdrm_writereg(priv, OCFB_CTRL, ctrl); > >> +} > >> + > >> +static bool ocdrm_crtc_mode_fixup(struct drm_crtc *crtc, > >> + const struct drm_display_mode *mode, > >> + struct drm_display_mode *adjusted_mode) > >> +{ > >> + struct ocdrm_priv *priv = crtc_to_ocdrm(crtc); > >> + > >> + if (mode->clock < 16000 || mode->clock > 165000) > >> + return false; > >> + > >> + adjusted_mode->clock = clk_round_rate(priv->pixel_clock, > >> + mode->clock * 1000) / 1000; > >> + return true; > >> +} > >> + > >> +static int ocdrm_crtc_atomic_check(struct drm_crtc *crtc, > >> + struct drm_crtc_state *state) > >> +{ > >> + struct ocdrm_priv *priv = crtc_to_ocdrm(crtc); > >> + struct drm_display_mode *m = &state->adjusted_mode; > >> + uint32_t hsync_len = m->crtc_hsync_end - m->crtc_hsync_start; > >> + uint32_t vsync_len = m->crtc_vsync_end - m->crtc_vsync_start; > >> + uint32_t vback_porch = m->crtc_vtotal - m->crtc_vsync_end; > >> + uint32_t hback_porch = m->crtc_htotal - m->crtc_hsync_end; > >> + int rate; > >> + > >> + if (m->clock < 16000 || m->clock > 165000) > >> + return false; > >> + > >> + rate = clk_round_rate(priv->pixel_clock, m->clock * 1000) / 1000; > >> + > >> + if (m->clock != rate) > >> + return -EINVAL; > >> + > >> + if (hsync_len > 255 || vsync_len > 255 || > >> + vback_porch > 255 || hback_porch > 255) > >> + return -EINVAL; > >> + > >> + return 0; > >> +} > >> + > >> +static struct drm_crtc_helper_funcs ocdrm_crtc_helper_funcs = { > >> + .mode_fixup = ocdrm_crtc_mode_fixup, > >> + .mode_set = drm_helper_crtc_mode_set, > >> + .mode_set_base = drm_helper_crtc_mode_set_base, > > > > You don't need the above 2 callbacks when exlusively using atomic. > > > >> + .mode_set_nofb = ocdrm_crtc_mode_set_nofb, > >> + .disable = ocdrm_crtc_disable, > >> + .enable = ocdrm_crtc_enable, > >> + .atomic_check = ocdrm_crtc_atomic_check, > >> +}; > >> + > >> +static void ocdrm_crtc_destroy(struct drm_crtc *crtc) > >> +{ > >> + ocdrm_crtc_disable(crtc); > >> + drm_crtc_cleanup(crtc); > >> +} > >> + > >> +static struct drm_crtc_funcs ocdrm_crtc_funcs = { > >> + .page_flip = drm_atomic_helper_page_flip, > >> + .set_config = drm_atomic_helper_set_config, > >> + .destroy = ocdrm_crtc_destroy, > >> + .reset = drm_atomic_helper_crtc_reset, > >> + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, > >> + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state > >> +}; > >> + > >> +static const struct drm_plane_helper_funcs ocdrm_plane_helper_funcs = { > >> + .atomic_update = ocdrm_plane_atomic_update, > >> + .atomic_disable = NULL, > >> + .prepare_fb = NULL, > >> + .cleanup_fb = NULL > > > > Don't set to NULL, that's always the case for global data. > > > >> +}; > >> + > >> +static const struct drm_plane_funcs ocdrm_plane_funcs = { > >> + .update_plane = drm_atomic_helper_update_plane, > >> + .disable_plane = drm_atomic_helper_disable_plane, > >> + .destroy = drm_plane_cleanup, > >> + .reset = drm_atomic_helper_plane_reset, > >> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, > >> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, > >> +}; > >> + > >> +int ocdrm_crtc_create(struct ocdrm_priv *priv) > >> +{ > >> + int ret; > >> + uint32_t format[] = { DRM_FORMAT_RGB565, > >> + DRM_FORMAT_RGB888, > >> + DRM_FORMAT_XRGB8888, > >> + }; > >> + > >> + drm_plane_helper_add(&priv->plane, &ocdrm_plane_helper_funcs); > >> + > >> + ret = drm_universal_plane_init(priv->drm_dev, &priv->plane, 0, > >> + &ocdrm_plane_funcs, > >> + format, ARRAY_SIZE(format), > >> + DRM_PLANE_TYPE_PRIMARY, NULL); > >> + if (ret) { > >> + dev_err(priv->drm_dev->dev, "cannot initialize plane"); > >> + return ret; > >> + } > >> + > >> + drm_crtc_helper_add(&priv->crtc, &ocdrm_crtc_helper_funcs); > >> + ret = drm_crtc_init_with_planes(priv->drm_dev, &priv->crtc, > >> + &priv->plane, NULL, > >> + &ocdrm_crtc_funcs, NULL); > >> + if (ret) > >> + dev_err(priv->drm_dev->dev, "cannot initialize crtc"); > >> + return ret; > >> + > >> + return 0; > >> +} > >> diff --git a/drivers/gpu/drm/ocdrm/ocdrm_crtc.h b/drivers/gpu/drm/ocdrm/ocdrm_crtc.h > >> new file mode 100644 > >> index 0000000..778327e > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/ocdrm_crtc.h > >> @@ -0,0 +1,48 @@ > >> +/* > >> + * Open cores VGA/LCD 2.0 core DRM driver > >> + * Copyright (c) 2016 Istituto Italiano di Tecnologia > >> + * Electronic Design Lab. > >> + * > >> + * Author: Andrea Merello > >> + * > >> + * Based on the following drivers: > >> + * - Analog Devices AXI HDMI DRM driver, which is > >> + * Copyright 2012 Analog Devices Inc. > >> + * > >> + * - ARC PGU DRM driver. > >> + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) > >> + * > >> + * - ARM HDLCD Driver > >> + * Copyright (C) 2013-2015 ARM Limited > >> + * > >> + * - Atmel atmel-hlcdc driver, which is > >> + * Copyright (C) 2014 Traphandler > >> + * Copyright (C) 2014 Free Electrons > >> + * > >> + * - OpenCores VGA/LCD 2.0 core frame buffer driver > >> + * Copyright (C) 2013 Stefan Kristiansson, stefan.kristiansson@saunalahti.fi > >> + * > >> + * - R-Car Display Unit DRM driver > >> + * Copyright (C) 2013-2015 Renesas Electronics Corporation > >> + * > >> + * This program is free software; you can redistribute it and/or modify it > >> + * under the terms of the GNU General Public License version 2 as published by > >> + * the Free Software Foundation. > >> + * > >> + * This program is distributed in the hope that 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, see . > >> + */ > >> + > >> +#ifndef _OCDRM_CRTC_H_ > >> +#define _OCDRM_CRTC_H_ > >> + > >> +#include "ocdrm_drv.h" > >> + > >> +int ocdrm_crtc_create(struct ocdrm_priv *priv); > >> + > >> +#endif > >> diff --git a/drivers/gpu/drm/ocdrm/ocdrm_drv.c b/drivers/gpu/drm/ocdrm/ocdrm_drv.c > >> new file mode 100644 > >> index 0000000..4b335dc > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/ocdrm_drv.c > >> @@ -0,0 +1,312 @@ > >> +/* > >> + * Open cores VGA/LCD 2.0 core DRM driver > >> + * Copyright (c) 2016 Istituto Italiano di Tecnologia > >> + * Electronic Design Lab. > >> + * > >> + * Author: Andrea Merello > >> + * > >> + * Based on the following drivers: > >> + * - Analog Devices AXI HDMI DRM driver, which is > >> + * Copyright 2012 Analog Devices Inc. > >> + * > >> + * - ARC PGU DRM driver. > >> + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) > >> + * > >> + * - ARM HDLCD Driver > >> + * Copyright (C) 2013-2015 ARM Limited > >> + * > >> + * - Atmel atmel-hlcdc driver, which is > >> + * Copyright (C) 2014 Traphandler > >> + * Copyright (C) 2014 Free Electrons > >> + * > >> + * - OpenCores VGA/LCD 2.0 core frame buffer driver > >> + * Copyright (C) 2013 Stefan Kristiansson, stefan.kristiansson@saunalahti.fi > >> + * > >> + * - R-Car Display Unit DRM driver > >> + * Copyright (C) 2013-2015 Renesas Electronics Corporation > >> + * > >> + * This program is free software; you can redistribute it and/or modify it > >> + * under the terms of the GNU General Public License version 2 as published by > >> + * the Free Software Foundation. > >> + * > >> + * This program is distributed in the hope that 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, see . > >> + */ > >> + > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> + > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> + > >> +#include "ocdrm_drv.h" > >> +#include "ocdrm_crtc.h" > >> +#include "ocdrm_encoder.h" > >> + > >> +#define DRIVER_NAME "ocdrm" > >> +#define DRIVER_DESC "OpenCores DRM" > >> +#define DRIVER_DATE "20160527" > >> +#define DRIVER_MAJOR 1 > >> +#define DRIVER_MINOR 0 > >> + > >> +static void ocdrm_output_poll_changed(struct drm_device *drm) > >> +{ > >> + struct ocdrm_priv *priv = drm->dev_private; > >> + > >> + drm_fbdev_cma_hotplug_event(priv->fbdev); > >> +} > >> + > >> +static int ocdrm_atomic_commit(struct drm_device *dev, > >> + struct drm_atomic_state *state, bool async) > >> +{ > >> + return drm_atomic_helper_commit(dev, state, false); > >> +} > >> + > >> +static struct drm_mode_config_funcs ocdrm_mode_config_funcs = { > >> + .output_poll_changed = ocdrm_output_poll_changed, > >> + .fb_create = drm_fb_cma_create, > >> + .atomic_check = drm_atomic_helper_check, > >> + .atomic_commit = ocdrm_atomic_commit, > > > > Just use drm_atomic_helper_commit please, there's patches in-flight to > > give you nonblocking atomic for free. Cheating with the above trick (like > > arcpgu does) needs to stop. > > > >> +}; > >> + > >> +u32 ocdrm_readreg(struct ocdrm_priv *priv, loff_t offset) > >> +{ > >> + if (priv->little_endian) > >> + return ioread32(priv->regs + offset); > >> + else > >> + return ioread32be(priv->regs + offset); > >> +} > >> + > >> +void ocdrm_writereg(struct ocdrm_priv *priv, loff_t offset, u32 data) > >> +{ > >> + if (priv->little_endian) > >> + iowrite32(data, priv->regs + offset); > >> + else > >> + iowrite32be(data, priv->regs + offset); > >> +} > >> + > >> +static void ocdrm_mode_config_init(struct ocdrm_priv *priv) > >> +{ > >> + struct drm_device *dev = priv->drm_dev; > >> + > >> + dev->mode_config.min_width = 0; > >> + dev->mode_config.min_height = 0; > >> + > >> + dev->mode_config.max_width = 1500; > >> + dev->mode_config.max_height = 1500; > >> + > >> + dev->mode_config.funcs = &ocdrm_mode_config_funcs; > >> +} > >> + > >> +static void ocdrm_detect_endian(struct ocdrm_priv *priv) > >> +{ > >> + priv->little_endian = false; > >> + ocdrm_writereg(priv, OCFB_VBARA, 0xfffffff0); > >> + if (ocdrm_readreg(priv, OCFB_VBARA) != 0xfffffff0) > >> + priv->little_endian = true; > >> + > >> + ocdrm_writereg(priv, OCFB_VBARA, 0x0); > >> +} > >> + > >> +static int ocdrm_load(struct drm_device *dev) > >> +{ > >> + struct ocdrm_priv *priv; > >> + int ret; > >> + struct resource *res; > >> + struct platform_device *pdev = to_platform_device(dev->dev); > >> + > >> + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); > >> + if (!priv) > >> + return -ENOMEM; > >> + dev->dev_private = priv; > >> + priv->drm_dev = dev; > >> + > >> + priv->pixel_clock = devm_clk_get(&pdev->dev, NULL); > >> + if (IS_ERR(priv->pixel_clock)) > >> + return -EPROBE_DEFER; > >> + > >> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > >> + priv->regs = devm_ioremap_resource(&pdev->dev, res); > >> + if (IS_ERR(priv->regs)) > >> + return PTR_ERR(priv->regs); > >> + > >> + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) > >> + return -ENOMEM; > >> + > >> + ocdrm_detect_endian(priv); > >> + > >> + drm_mode_config_init(dev); > >> + ocdrm_mode_config_init(priv); > >> + > >> + ret = ocdrm_crtc_create(priv); > >> + if (ret) > >> + goto err_crtc; > >> + > >> + ret = ocdrm_encoder_create(priv); > >> + if (ret) > >> + goto err_crtc; > >> + > >> + drm_mode_config_reset(dev); > >> + drm_kms_helper_poll_init(dev); > >> + > >> + priv->fbdev = drm_fbdev_cma_init(dev, 16, dev->mode_config.num_crtc, > >> + dev->mode_config.num_connector); > >> + > >> + if (IS_ERR(priv->fbdev)) { > >> + DRM_ERROR("failed to initialize drm fbdev\n"); > >> + ret = PTR_ERR(priv->fbdev); > >> + goto err_crtc; > >> + } > >> + > >> + platform_set_drvdata(pdev, priv); > >> + return 0; > >> + > >> +err_crtc: > >> + drm_mode_config_cleanup(dev); > >> + return ret; > >> +} > >> + > >> +static int ocdrm_unload(struct drm_device *dev) > >> +{ > >> + struct ocdrm_priv *priv = dev->dev_private; > >> + > >> + if (priv->fbdev) { > >> + drm_fbdev_cma_fini(priv->fbdev); > >> + priv->fbdev = NULL; > >> + } > >> + drm_kms_helper_poll_fini(dev); > >> + drm_vblank_cleanup(dev); > >> + drm_mode_config_cleanup(dev); > >> + > >> + return 0; > >> +} > >> + > >> +static void ocdrm_lastclose(struct drm_device *dev) > >> +{ > >> + struct ocdrm_priv *priv = dev->dev_private; > >> + > >> + drm_fbdev_cma_restore_mode(priv->fbdev); > >> +} > >> + > >> +static const struct file_operations ocdrm_driver_fops = { > >> + .owner = THIS_MODULE, > >> + .open = drm_open, > >> + .mmap = drm_gem_cma_mmap, > >> + .poll = drm_poll, > >> + .read = drm_read, > >> + .unlocked_ioctl = drm_ioctl, > >> +#ifdef CONFIG_COMPAT > >> + .compat_ioctl = drm_compat_ioctl, > >> +#endif > >> + .llseek = no_llseek, > >> + .release = drm_release, > >> +}; > >> + > >> +static struct drm_driver ocdrm_drm_driver = { > >> + .driver_features = DRIVER_MODESET | DRIVER_GEM | > >> + DRIVER_ATOMIC | DRIVER_PRIME, > >> + .lastclose = ocdrm_lastclose, > >> + .fops = &ocdrm_driver_fops, > >> + .name = DRIVER_NAME, > >> + .desc = DRIVER_DESC, > >> + .date = DRIVER_DATE, > >> + .major = DRIVER_MAJOR, > >> + .minor = DRIVER_MINOR, > >> + .dumb_create = drm_gem_cma_dumb_create, > >> + .dumb_map_offset = drm_gem_cma_dumb_map_offset, > >> + .dumb_destroy = drm_gem_dumb_destroy, > >> + .get_vblank_counter = drm_vblank_no_hw_counter, > >> + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, > >> + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, > >> + .gem_free_object = drm_gem_cma_free_object, > >> + .gem_vm_ops = &drm_gem_cma_vm_ops, > >> + .gem_prime_export = drm_gem_prime_export, > >> + .gem_prime_import = drm_gem_prime_import, > >> + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, > >> + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, > >> + .gem_prime_vmap = drm_gem_cma_prime_vmap, > >> + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, > >> + .gem_prime_mmap = drm_gem_cma_prime_mmap, > >> + > >> +}; > >> + > >> +static const struct of_device_id ocdrm_of_match[] = { > >> + { .compatible = "opencores,ocfb-drm", }, > >> + {}, > >> +}; > >> +MODULE_DEVICE_TABLE(of, ocdrm_of_match); > >> + > >> +static int ocdrm_probe(struct platform_device *pdev) > >> +{ > >> + int ret; > >> + struct drm_device *drm; > >> + > >> + drm = drm_dev_alloc(&ocdrm_drm_driver, &pdev->dev); > >> + if (!drm) > >> + return -ENOMEM; > >> + > >> + ret = ocdrm_load(drm); > >> + if (ret) > >> + goto err_unref; > >> + > >> + ret = drm_dev_register(drm, 0); > >> + if (ret) > >> + goto err_unload; > >> + > >> + ret = drm_connector_register_all(drm); > >> + if (ret) > >> + goto err_unregister; > >> + return 0; > >> + > >> +err_unregister: > >> + drm_dev_unregister(drm); > >> +err_unload: > >> + ocdrm_unload(drm); > >> +err_unref: > >> + drm_dev_unref(drm); > >> + > >> + return ret; > >> +} > >> + > >> +static int ocdrm_remove(struct platform_device *pdev) > >> +{ > >> + struct ocdrm_priv *priv = platform_get_drvdata(pdev); > >> + struct drm_device *drm = priv->drm_dev; > >> + > >> + drm_connector_unregister_all(priv->drm_dev); > >> + drm_dev_unregister(drm); > >> + ocdrm_unload(drm); > >> + drm_dev_unref(drm); > >> + > >> + return 0; > >> +} > >> + > >> +static struct platform_driver ocdrm_platform_driver = { > >> + .driver = { > >> + .name = "oc-drm", > >> + .owner = THIS_MODULE, > >> + .of_match_table = ocdrm_of_match, > >> + }, > >> + .probe = ocdrm_probe, > >> + .remove = ocdrm_remove, > >> +}; > >> +module_platform_driver(ocdrm_platform_driver); > >> + > >> +MODULE_LICENSE("GPL v2"); > >> +MODULE_AUTHOR("Andrea Merello "); > >> +MODULE_DESCRIPTION("OpenCores DRM driver"); > >> diff --git a/drivers/gpu/drm/ocdrm/ocdrm_drv.h b/drivers/gpu/drm/ocdrm/ocdrm_drv.h > >> new file mode 100644 > >> index 0000000..14e5539 > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/ocdrm_drv.h > >> @@ -0,0 +1,89 @@ > >> +/* > >> + * Open cores VGA/LCD 2.0 core DRM driver > >> + * Copyright (c) 2016 Istituto Italiano di Tecnologia > >> + * Electronic Design Lab. > >> + * > >> + * Author: Andrea Merello > >> + * > >> + * Based on the following drivers: > >> + * - Analog Devices AXI HDMI DRM driver, which is > >> + * Copyright 2012 Analog Devices Inc. > >> + * > >> + * - ARC PGU DRM driver. > >> + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) > >> + * > >> + * - ARM HDLCD Driver > >> + * Copyright (C) 2013-2015 ARM Limited > >> + * > >> + * - Atmel atmel-hlcdc driver, which is > >> + * Copyright (C) 2014 Traphandler > >> + * Copyright (C) 2014 Free Electrons > >> + * > >> + * - OpenCores VGA/LCD 2.0 core frame buffer driver > >> + * Copyright (C) 2013 Stefan Kristiansson, stefan.kristiansson@saunalahti.fi > >> + * > >> + * - R-Car Display Unit DRM driver > >> + * Copyright (C) 2013-2015 Renesas Electronics Corporation > >> + * > >> + * This program is free software; you can redistribute it and/or modify it > >> + * under the terms of the GNU General Public License version 2 as published by > >> + * the Free Software Foundation. > >> + * > >> + * This program is distributed in the hope that 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, see . > >> + */ > >> + > >> +#ifndef _OCDRM_DRV_H_ > >> +#define _OCDRM_DRV_H_ > >> + > >> +#include > >> +#include > >> +#include > >> +#include > >> + > >> +/* OCFB register defines */ > >> +#define OCFB_CTRL 0x000 > >> +#define OCFB_STAT 0x004 > >> +#define OCFB_HTIM 0x008 > >> +#define OCFB_VTIM 0x00c > >> +#define OCFB_HVLEN 0x010 > >> +#define OCFB_VBARA 0x014 > >> +#define OCFB_PALETTE 0x800 > >> + > >> +#define OCFB_CTRL_VEN 0x00000001 /* Video Enable */ > >> +#define OCFB_CTRL_HIE 0x00000002 /* HSync Interrupt Enable */ > >> +#define OCFB_CTRL_PC 0x00000800 /* 8-bit Pseudo Color Enable*/ > >> +#define OCFB_CTRL_CD8 0x00000000 /* Color Depth 8 */ > >> +#define OCFB_CTRL_CD16 0x00000200 /* Color Depth 16 */ > >> +#define OCFB_CTRL_CD24 0x00000400 /* Color Depth 24 */ > >> +#define OCFB_CTRL_CD32 0x00000600 /* Color Depth 32 */ > >> +#define OCFB_CTRL_VBL1 0x00000000 /* Burst Length 1 */ > >> +#define OCFB_CTRL_VBL2 0x00000080 /* Burst Length 2 */ > >> +#define OCFB_CTRL_VBL4 0x00000100 /* Burst Length 4 */ > >> +#define OCFB_CTRL_VBL8 0x00000180 /* Burst Length 8 */ > >> +#define OCFB_CTRL_HSL 0x00001000 /* HSync active low */ > >> +#define OCFB_CTRL_VSL 0x00002000 /* VSync active low */ > >> + > >> +#define PALETTE_SIZE 256 > >> + > >> +struct ocdrm_priv { > >> + struct drm_device *drm_dev; > >> + struct drm_fbdev_cma *fbdev; > >> + struct drm_crtc crtc; > >> + struct drm_plane plane; > >> + struct drm_encoder encoder; > >> + struct clk *pixel_clock; > >> + bool clk_enabled; > >> + void __iomem *regs; > >> + bool little_endian; > >> +}; > >> + > >> +extern void ocdrm_writereg(struct ocdrm_priv *priv, loff_t offset, u32 data); > >> +extern u32 ocdrm_readreg(struct ocdrm_priv *priv, loff_t offset); > >> + > >> +#endif > >> diff --git a/drivers/gpu/drm/ocdrm/ocdrm_encoder.c b/drivers/gpu/drm/ocdrm/ocdrm_encoder.c > >> new file mode 100644 > >> index 0000000..f157bb5 > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/ocdrm_encoder.c > >> @@ -0,0 +1,95 @@ > >> +/* > >> + * Open cores VGA/LCD 2.0 core DRM driver > >> + * Copyright (c) 2016 Istituto Italiano di Tecnologia > >> + * Electronic Design Lab. > >> + * > >> + * Author: Andrea Merello > >> + * > >> + * Based on the following drivers: > >> + * - Analog Devices AXI HDMI DRM driver, which is > >> + * Copyright 2012 Analog Devices Inc. > >> + * > >> + * - ARC PGU DRM driver. > >> + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) > >> + * > >> + * - ARM HDLCD Driver > >> + * Copyright (C) 2013-2015 ARM Limited > >> + * > >> + * - Atmel atmel-hlcdc driver, which is > >> + * Copyright (C) 2014 Traphandler > >> + * Copyright (C) 2014 Free Electrons > >> + * > >> + * - OpenCores VGA/LCD 2.0 core frame buffer driver > >> + * Copyright (C) 2013 Stefan Kristiansson, stefan.kristiansson@saunalahti.fi > >> + * > >> + * - R-Car Display Unit DRM driver > >> + * Copyright (C) 2013-2015 Renesas Electronics Corporation > >> + * > >> + * This program is free software; you can redistribute it and/or modify it > >> + * under the terms of the GNU General Public License version 2 as published by > >> + * the Free Software Foundation. > >> + * > >> + * This program is distributed in the hope that 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, see . > >> + */ > >> + > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include > >> +#include "ocdrm_encoder.h" > >> + > >> +static void ocdrm_encoder_nop(struct drm_encoder *encoder) > >> +{ > >> +} > >> + > >> +static const struct drm_encoder_funcs ocdrm_encoder_funcs = { > >> + .destroy = drm_encoder_cleanup > >> +}; > >> + > >> +static struct drm_encoder_helper_funcs ocdrm_encoder_helper_funcs = { > >> + .commit = ocdrm_encoder_nop, > >> + .enable = ocdrm_encoder_nop, > >> + .disable = ocdrm_encoder_nop > >> +}; > > > > Please nuke all these no-op functions. Even more so, just nuke the entire > > helper struct, it can be NULL. > >> + > >> +int ocdrm_encoder_create(struct ocdrm_priv *priv) > >> +{ > >> + struct drm_encoder *encoder; > >> + struct drm_bridge *bridge; > >> + struct device_node *ep, *bridge_node; > >> + int ret; > >> + > >> + encoder = &priv->encoder; > >> + encoder->possible_crtcs = 1 << drm_crtc_index(&priv->crtc); > >> + > >> + drm_encoder_helper_add(encoder, &ocdrm_encoder_helper_funcs); > >> + ret = drm_encoder_init(priv->drm_dev, encoder, &ocdrm_encoder_funcs, > >> + DRM_MODE_ENCODER_NONE, NULL); > >> + if (ret) > >> + return ret; > >> + ep = of_graph_get_next_endpoint(priv->drm_dev->dev->of_node, NULL); > >> + if (!ep) > >> + return -ENODEV; > >> + > >> + bridge_node = of_graph_get_remote_port_parent(ep); > >> + if (!bridge_node) > >> + return -ENODEV; > >> + > >> + bridge = of_drm_find_bridge(bridge_node); > >> + if (!bridge) > >> + return -EPROBE_DEFER; > >> + > >> + bridge->encoder = encoder; > >> + encoder->bridge = bridge; > >> + drm_bridge_attach(priv->drm_dev, bridge); > >> + return 0; > >> +} > >> diff --git a/drivers/gpu/drm/ocdrm/ocdrm_encoder.h b/drivers/gpu/drm/ocdrm/ocdrm_encoder.h > >> new file mode 100644 > >> index 0000000..a5ee5f6 > >> --- /dev/null > >> +++ b/drivers/gpu/drm/ocdrm/ocdrm_encoder.h > >> @@ -0,0 +1,48 @@ > >> +/* > >> + * Open cores VGA/LCD 2.0 core DRM driver > >> + * Copyright (c) 2016 Istituto Italiano di Tecnologia > >> + * Electronic Design Lab. > >> + * > >> + * Author: Andrea Merello > >> + * > >> + * Based on the following drivers: > >> + * - Analog Devices AXI HDMI DRM driver, which is > >> + * Copyright 2012 Analog Devices Inc. > >> + * > >> + * - ARC PGU DRM driver. > >> + * Copyright (C) 2016 Synopsys, Inc. (www.synopsys.com) > >> + * > >> + * - ARM HDLCD Driver > >> + * Copyright (C) 2013-2015 ARM Limited > >> + * > >> + * - Atmel atmel-hlcdc driver, which is > >> + * Copyright (C) 2014 Traphandler > >> + * Copyright (C) 2014 Free Electrons > >> + * > >> + * - OpenCores VGA/LCD 2.0 core frame buffer driver > >> + * Copyright (C) 2013 Stefan Kristiansson, stefan.kristiansson@saunalahti.fi > >> + * > >> + * - R-Car Display Unit DRM driver > >> + * Copyright (C) 2013-2015 Renesas Electronics Corporation > >> + * > >> + * This program is free software; you can redistribute it and/or modify it > >> + * under the terms of the GNU General Public License version 2 as published by > >> + * the Free Software Foundation. > >> + * > >> + * This program is distributed in the hope that 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, see . > >> + */ > >> + > >> +#ifndef _OCDRM_ENCODER_H_ > >> +#define _OCDRM_ENCODER_H_ > >> + > >> +#include "ocdrm_drv.h" > >> + > >> +int ocdrm_encoder_create(struct ocdrm_priv *priv); > >> + > >> +#endif > >> -- > >> 1.9.1 > >> > >> _______________________________________________ > >> dri-devel mailing list > >> dri-devel@lists.freedesktop.org > >> https://lists.freedesktop.org/mailman/listinfo/dri-devel > > > > -- > > Daniel Vetter > > Software Engineer, Intel Corporation > > http://blog.ffwll.ch > _______________________________________________ > dri-devel mailing list > dri-devel@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch