From patchwork Mon Jan 16 13:28:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick FERTRE X-Patchwork-Id: 9518779 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 96A986020B for ; Mon, 16 Jan 2017 13:29:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7745B28387 for ; Mon, 16 Jan 2017 13:29:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6BC7828452; Mon, 16 Jan 2017 13:29:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EAD0D28387 for ; Mon, 16 Jan 2017 13:29:43 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id CCC076E33D; Mon, 16 Jan 2017 13:29:40 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3B7D16E33D for ; Mon, 16 Jan 2017 13:29:35 +0000 (UTC) Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id v0GDNnS4028804; Mon, 16 Jan 2017 14:29:13 +0100 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-.pphosted.com with ESMTP id 27ybrht702-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Mon, 16 Jan 2017 14:29:13 +0100 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 54B0A34; Mon, 16 Jan 2017 13:29:12 +0000 (GMT) Received: from Webmail-eu.st.com (Safex1hubcas23.st.com [10.75.90.46]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 2D82329DC; Mon, 16 Jan 2017 13:29:11 +0000 (GMT) Received: from localhost (10.48.1.53) by webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.319.2; Mon, 16 Jan 2017 14:29:10 +0100 From: Yannick Fertre To: Alexandre TORGUE , Thierry Reding , David Airlie , Maxime Coquelin , Russell King , Mark Rutland , Rob Herring , Arnd Bergmann Subject: [PATCH v1 2/7] drm/st: Add STM32 LTDC driver Date: Mon, 16 Jan 2017 14:28:59 +0100 Message-ID: <1484573344-11609-3-git-send-email-yannick.fertre@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1484573344-11609-1-git-send-email-yannick.fertre@st.com> References: <1484573344-11609-1-git-send-email-yannick.fertre@st.com> MIME-Version: 1.0 X-Originating-IP: [10.48.1.53] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-01-16_11:, , signatures=0 Cc: devicetree@vger.kernel.org, kernel@stlinux.com, Philippe Cornu , dri-devel@lists.freedesktop.org, Mickael Reulier , Gabriel FERNANDEZ , linux-arm-kernel@lists.infradead.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for the STM32 LCD-TFT display controller. Signed-off-by: Yannick Fertre --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/st/Kconfig | 14 + drivers/gpu/drm/st/Makefile | 7 + drivers/gpu/drm/st/drv.c | 279 +++++++++ drivers/gpu/drm/st/drv.h | 25 + drivers/gpu/drm/st/ltdc.c | 1438 +++++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/st/ltdc.h | 20 + 8 files changed, 1786 insertions(+) create mode 100644 drivers/gpu/drm/st/Kconfig create mode 100644 drivers/gpu/drm/st/Makefile create mode 100644 drivers/gpu/drm/st/drv.c create mode 100644 drivers/gpu/drm/st/drv.h create mode 100644 drivers/gpu/drm/st/ltdc.c create mode 100644 drivers/gpu/drm/st/ltdc.h diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 6f3f9e6..d8e6f92 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -237,6 +237,8 @@ source "drivers/gpu/drm/fsl-dcu/Kconfig" source "drivers/gpu/drm/tegra/Kconfig" +source "drivers/gpu/drm/st/Kconfig" + source "drivers/gpu/drm/panel/Kconfig" source "drivers/gpu/drm/bridge/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 92de399..7434c09 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/ obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_TEGRA) += tegra/ +obj-$(CONFIG_DRM_ST) += st/ obj-$(CONFIG_DRM_STI) += sti/ obj-$(CONFIG_DRM_IMX) += imx/ obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ diff --git a/drivers/gpu/drm/st/Kconfig b/drivers/gpu/drm/st/Kconfig new file mode 100644 index 0000000..fa0ac0c --- /dev/null +++ b/drivers/gpu/drm/st/Kconfig @@ -0,0 +1,14 @@ +config DRM_ST + tristate "DRM Support for STMicroelectronics SoC Series" + depends on DRM && (ARCH_STM32 || ARCH_MULTIPLATFORM) + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + select DRM_PANEL + select VIDEOMODE_HELPERS + select FB_PROVIDE_GET_FB_UNMAPPED_AREA + help + Choose this option if you have an ST STMicroelectronics SoC. + + To compile this driver as a module, choose M here: the module + will be called st-drm. diff --git a/drivers/gpu/drm/st/Makefile b/drivers/gpu/drm/st/Makefile new file mode 100644 index 0000000..b2a9025 --- /dev/null +++ b/drivers/gpu/drm/st/Makefile @@ -0,0 +1,7 @@ +ccflags-y := -Iinclude/drm + +st-drm-y := \ + drv.o \ + ltdc.o + +obj-$(CONFIG_DRM_ST) += st-drm.o diff --git a/drivers/gpu/drm/st/drv.c b/drivers/gpu/drm/st/drv.c new file mode 100644 index 0000000..a275019 --- /dev/null +++ b/drivers/gpu/drm/st/drv.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) STMicroelectronics SA 2017 + * + * Authors: Philippe Cornu + * Yannick Fertre + * Fabien Dessenne + * Mickael Reulier + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "drv.h" +#include "ltdc.h" + +#define DRIVER_NAME "st" +#define DRIVER_DESC "STMicroelectronics SoC DRM" +#define DRIVER_DATE "20170110" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +#define ST_MAX_FB_WIDTH 2048 +#define ST_MAX_FB_HEIGHT 2048 /* same as width to handle orientation */ + +static void st_output_poll_changed(struct drm_device *ddev) +{ + struct st_private *priv = ddev->dev_private; + + drm_fbdev_cma_hotplug_event(priv->fbdev); +} + +static const struct drm_mode_config_funcs st_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .output_poll_changed = st_output_poll_changed, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static void st_mode_config_init(struct drm_device *ddev) +{ + ddev->mode_config.min_width = 0; + ddev->mode_config.min_height = 0; + + /* + * set max width and height as default value. + * this value would be used to check framebuffer size limitation + * at drm_mode_addfb(). + */ + ddev->mode_config.max_width = ST_MAX_FB_WIDTH; + ddev->mode_config.max_height = ST_MAX_FB_HEIGHT; + ddev->mode_config.funcs = &st_mode_config_funcs; +} + +static const struct file_operations st_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .get_unmapped_area = drm_gem_cma_get_unmapped_area, + .mmap = drm_gem_cma_mmap, + .poll = drm_poll, + .read = drm_read, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .release = drm_release, +}; + +static struct drm_driver st_driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | + DRIVER_ATOMIC, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + .fops = &st_driver_fops, + + .get_vblank_counter = drm_vblank_no_hw_counter, + .enable_vblank = ltdc_crtc_enable_vblank, + .disable_vblank = ltdc_crtc_disable_vblank, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .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, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, +}; + +static int compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static int st_init(struct drm_device *ddev) +{ + struct st_private *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ddev->dev_private = (void *)priv; + dev_set_drvdata(ddev->dev, ddev); + priv->ddev = ddev; + + drm_mode_config_init(ddev); + + st_mode_config_init(ddev); + + drm_kms_helper_poll_init(ddev); + + return 0; +} + +static void st_cleanup(struct drm_device *ddev) +{ + struct st_private *priv = ddev->dev_private; + + if (priv->fbdev) { + drm_fbdev_cma_fini(priv->fbdev); + priv->fbdev = NULL; + } + + drm_kms_helper_poll_fini(ddev); + drm_vblank_cleanup(ddev); + kfree(priv); + ddev->dev_private = NULL; +} + +static int st_bind(struct device *dev) +{ + struct drm_device *ddev; + struct st_private *priv; + struct drm_fbdev_cma *fbdev; + int ret; + + ddev = drm_dev_alloc(&st_driver, dev); + if (IS_ERR(ddev)) + return PTR_ERR(ddev); + + ddev->platformdev = to_platform_device(dev); + + ret = st_init(ddev); + if (ret) + goto err_drm_dev_unref; + + ret = component_bind_all(ddev->dev, ddev); + if (ret) + goto err_cleanup; + + ret = drm_dev_register(ddev, 0); + if (ret) + goto err_register; + + drm_mode_config_reset(ddev); + + if (ddev->mode_config.num_connector) { + priv = ddev->dev_private; + fbdev = drm_fbdev_cma_init(ddev, 16, + ddev->mode_config.num_crtc, + ddev->mode_config.num_connector); + if (IS_ERR(fbdev)) { + DRM_DEBUG_DRIVER("Warning: fails to create fbdev\n"); + fbdev = NULL; + } + priv->fbdev = fbdev; + } + + return 0; + +err_register: + component_unbind_all(ddev->dev, ddev); +err_cleanup: + st_cleanup(ddev); +err_drm_dev_unref: + drm_dev_unref(ddev); + return ret; +} + +static void st_unbind(struct device *dev) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + + drm_dev_unregister(ddev); + st_cleanup(ddev); + drm_dev_unref(ddev); +} + +static const struct component_master_ops st_ops = { + .bind = st_bind, + .unbind = st_unbind, +}; + +static int st_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *child_np; + struct component_match *match = NULL; + + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + + of_platform_populate(node, NULL, NULL, dev); + + child_np = of_get_next_available_child(node, NULL); + + while (child_np) { + component_match_add(dev, &match, compare_of, child_np); + of_node_put(child_np); + child_np = of_get_next_available_child(node, child_np); + } + + return component_master_add_with_match(dev, &st_ops, match); +} + +static int st_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &st_ops); + of_platform_depopulate(&pdev->dev); + + return 0; +} + +static const struct of_device_id st_dt_ids[] = { + { .compatible = "st,display-subsystem", }, + { /* end node */ }, +}; +MODULE_DEVICE_TABLE(of, st_dt_ids); + +static struct platform_driver st_platform_driver = { + .probe = st_platform_probe, + .remove = st_platform_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = st_dt_ids, + }, +}; + +static struct platform_driver * const drivers[] = { + <dc_driver, + &st_platform_driver, +}; + +static int st_drm_init(void) +{ + return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); +} +module_init(st_drm_init); + +static void st_drm_exit(void) +{ + platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); +} +module_exit(st_drm_exit); + +MODULE_AUTHOR("Philippe Cornu "); +MODULE_AUTHOR("Yannick Fertre "); +MODULE_AUTHOR("Fabien Dessenne "); +MODULE_AUTHOR("Mickael Reulier "); +MODULE_DESCRIPTION("STMicroelectronics ST DRM LTDC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/st/drv.h b/drivers/gpu/drm/st/drv.h new file mode 100644 index 0000000..d3da1bc --- /dev/null +++ b/drivers/gpu/drm/st/drv.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) STMicroelectronics SA 2017 + * + * Authors: Philippe Cornu + * Yannick Fertre + * Fabien Dessenne + * Mickael Reulier + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _DRV_H_ +#define _DRV_H_ + +#include + +struct st_private { + struct ltdc *ltdc; + struct drm_device *ddev; + struct drm_fbdev_cma *fbdev; +}; + +extern struct platform_driver ltdc_driver; + +#endif diff --git a/drivers/gpu/drm/st/ltdc.c b/drivers/gpu/drm/st/ltdc.c new file mode 100644 index 0000000..46a7ab2 --- /dev/null +++ b/drivers/gpu/drm/st/ltdc.c @@ -0,0 +1,1438 @@ +/* + * Copyright (C) STMicroelectronics SA 2017 + * + * Authors: Philippe Cornu + * Yannick Fertre + * Fabien Dessenne + * Mickael Reulier + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include