On Fri, Jun 10, 2016 at 4:27 PM, Daniel Vetter <daniel@xxxxxxxx> 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 <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 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/ > -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