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 <andrea.merello@xxxxxxxxx> > Cc: Stefan Kristiansson <stefan.kristiansson@xxxxxxxxxxxxx> > Cc: Tomi Valkeinen <tomi.valkeinen@xxxxxx> > Cc: Francesco Diotalevi <francesco.diotalevi@xxxxxx> > Cc: Claudio Lorini <claudio.lorini@xxxxxx> 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 -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 <andrea.merello@xxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxx > + * > + * - 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 <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/slab.h> > + > +#include <drm/drmP.h> > +#include <drm/drm_crtc_helper.h> > +#include <drm/drm_gem_cma_helper.h> > +#include <drm/drm_plane_helper.h> > +#include <drm/drm_crtc_helper.h> > +#include <drm/drm_atomic_helper.h> > + > +#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 <andrea.merello@xxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxx > + * > + * - 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 <http://www.gnu.org/licenses/>. > + */ > + > +#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 <andrea.merello@xxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxx > + * > + * - 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 <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/of.h> > +#include <linux/i2c.h> > +#include <linux/of_address.h> > +#include <linux/of_dma.h> > +#include <linux/clk.h> > + > +#include <drm/drmP.h> > +#include <drm/drm.h> > +#include <drm/drm_atomic.h> > +#include <drm/drm_atomic_helper.h> > +#include <drm/drm_crtc_helper.h> > +#include <drm/drm_gem_cma_helper.h> > + > +#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 <andrea.merello@xxxxxxxxx>"); > +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 <andrea.merello@xxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxx > + * > + * - 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 <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef _OCDRM_DRV_H_ > +#define _OCDRM_DRV_H_ > + > +#include <drm/drm.h> > +#include <drm/drm_fb_cma_helper.h> > +#include <linux/of.h> > +#include <linux/clk.h> > + > +/* 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 <andrea.merello@xxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxx > + * > + * - 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 <http://www.gnu.org/licenses/>. > + */ > + > +#include <linux/of.h> > +#include <linux/of_graph.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <drm/drmP.h> > +#include <drm/drm_crtc_helper.h> > +#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 <andrea.merello@xxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxx > + * > + * - 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 <http://www.gnu.org/licenses/>. > + */ > + > +#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@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/dri-devel -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel