From mboxrd@z Thu Jan 1 00:00:00 1970 From: narmstrong@baylibre.com (Neil Armstrong) Date: Fri, 14 Apr 2017 14:59:33 +0200 Subject: [PATCH v7 4/9] drm/stm: Add STM32 LTDC driver In-Reply-To: <1492164819-10513-5-git-send-email-yannick.fertre@st.com> References: <1492164819-10513-1-git-send-email-yannick.fertre@st.com> <1492164819-10513-5-git-send-email-yannick.fertre@st.com> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On 04/14/2017 12:13 PM, Yannick Fertre wrote: > This controller provides output signals to interface directly a variety > of LCD and TFT panels. These output signals are: RGB signals > (up to 24bpp), vertical & horizontal synchronisations, data enable and > the pixel clock. > > Reviewed-by: Eric Anholt > Signed-off-by: Yannick Fertre > --- > drivers/gpu/drm/Kconfig | 2 + > drivers/gpu/drm/Makefile | 1 + > drivers/gpu/drm/stm/Kconfig | 16 + > drivers/gpu/drm/stm/Makefile | 7 + > drivers/gpu/drm/stm/drv.c | 221 ++++++++ > drivers/gpu/drm/stm/ltdc.c | 1161 ++++++++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/stm/ltdc.h | 40 ++ > 7 files changed, 1448 insertions(+) > create mode 100644 drivers/gpu/drm/stm/Kconfig > create mode 100644 drivers/gpu/drm/stm/Makefile > create mode 100644 drivers/gpu/drm/stm/drv.c > create mode 100644 drivers/gpu/drm/stm/ltdc.c > create mode 100644 drivers/gpu/drm/stm/ltdc.h > > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig > index 78d7fc0..f57540d 100644 > --- a/drivers/gpu/drm/Kconfig > +++ b/drivers/gpu/drm/Kconfig > @@ -246,6 +246,8 @@ source "drivers/gpu/drm/fsl-dcu/Kconfig" > > source "drivers/gpu/drm/tegra/Kconfig" > > +source "drivers/gpu/drm/stm/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 59f0f9b..aa62ded 100644 > --- a/drivers/gpu/drm/Makefile > +++ b/drivers/gpu/drm/Makefile > @@ -82,6 +82,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_STM) += stm/ > obj-$(CONFIG_DRM_STI) += sti/ > obj-$(CONFIG_DRM_IMX) += imx/ > obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ > diff --git a/drivers/gpu/drm/stm/Kconfig b/drivers/gpu/drm/stm/Kconfig > new file mode 100644 > index 0000000..2c4817f > --- /dev/null > +++ b/drivers/gpu/drm/stm/Kconfig > @@ -0,0 +1,16 @@ > +config DRM_STM > + 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 > + default y > + > + help > + Enable support for the on-chip display controller on > + STMicroelectronics STM32 MCUs. > + To compile this driver as a module, choose M here: the module > + will be called stm-drm. > diff --git a/drivers/gpu/drm/stm/Makefile b/drivers/gpu/drm/stm/Makefile > new file mode 100644 > index 0000000..e114d45 > --- /dev/null > +++ b/drivers/gpu/drm/stm/Makefile > @@ -0,0 +1,7 @@ > +ccflags-y := -Iinclude/drm > + > +stm-drm-y := \ > + drv.o \ > + ltdc.o > + > +obj-$(CONFIG_DRM_STM) += stm-drm.o > diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c > new file mode 100644 > index 0000000..83ab48f > --- /dev/null > +++ b/drivers/gpu/drm/stm/drv.c > @@ -0,0 +1,221 @@ > +/* > + * 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 "ltdc.h" > + > +#define DRIVER_NAME "stm" > +#define DRIVER_DESC "STMicroelectronics SoC DRM" > +#define DRIVER_DATE "20170330" > +#define DRIVER_MAJOR 1 > +#define DRIVER_MINOR 0 > +#define DRIVER_PATCH_LEVEL 0 > + > +#define STM_MAX_FB_WIDTH 2048 > +#define STM_MAX_FB_HEIGHT 2048 /* same as width to handle orientation */ > + > +static void drv_output_poll_changed(struct drm_device *ddev) > +{ > + struct ltdc_device *ldev = ddev->dev_private; > + > + drm_fbdev_cma_hotplug_event(ldev->fbdev); > +} > + > +static const struct drm_mode_config_funcs drv_mode_config_funcs = { > + .fb_create = drm_fb_cma_create, > + .output_poll_changed = drv_output_poll_changed, > + .atomic_check = drm_atomic_helper_check, > + .atomic_commit = drm_atomic_helper_commit, > +}; > + > +static void drv_lastclose(struct drm_device *ddev) > +{ > + struct ltdc_device *ldev = ddev->dev_private; > + > + DRM_DEBUG("%s\n", __func__); > + > + drm_fbdev_cma_restore_mode(ldev->fbdev); > +} > + > +DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); > + > +static struct drm_driver drv_driver = { > + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | > + DRIVER_ATOMIC, > + .lastclose = drv_lastclose, > + .name = DRIVER_NAME, > + .desc = DRIVER_DESC, > + .date = DRIVER_DATE, > + .major = DRIVER_MAJOR, > + .minor = DRIVER_MINOR, > + .patchlevel = DRIVER_PATCH_LEVEL, > + .fops = &drv_driver_fops, > + .dumb_create = drm_gem_cma_dumb_create, > + .dumb_map_offset = drm_gem_cma_dumb_map_offset, > + .dumb_destroy = drm_gem_dumb_destroy, > + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, > + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, > + .gem_free_object_unlocked = 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, > + .enable_vblank = ltdc_crtc_enable_vblank, > + .disable_vblank = ltdc_crtc_disable_vblank, > +}; > + > +static int drv_load(struct drm_device *ddev) > +{ > + struct platform_device *pdev = to_platform_device(ddev->dev); > + struct drm_fbdev_cma *fbdev; > + struct ltdc_device *ldev; > + int ret; > + > + DRM_DEBUG("%s\n", __func__); > + > + ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL); > + if (!ldev) > + return -ENOMEM; > + > + ddev->dev_private = (void *)ldev; > + > + drm_mode_config_init(ddev); > + > + /* > + * 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.min_width = 0; > + ddev->mode_config.min_height = 0; > + ddev->mode_config.max_width = STM_MAX_FB_WIDTH; > + ddev->mode_config.max_height = STM_MAX_FB_HEIGHT; > + ddev->mode_config.funcs = &drv_mode_config_funcs; > + > + ret = ltdc_load(ddev); > + if (ret) > + goto err; > + > + drm_mode_config_reset(ddev); > + drm_kms_helper_poll_init(ddev); > + > + if (ddev->mode_config.num_connector) { > + ldev = ddev->dev_private; > + fbdev = drm_fbdev_cma_init(ddev, 16, > + ddev->mode_config.num_connector); > + if (IS_ERR(fbdev)) { > + DRM_DEBUG("Warning: fails to create fbdev\n"); > + fbdev = NULL; > + } > + ldev->fbdev = fbdev; > + } > + > + platform_set_drvdata(pdev, ddev); > + > + return 0; > +err: > + drm_mode_config_cleanup(ddev); > + return ret; > +} > + > +static void drv_unload(struct drm_device *ddev) > +{ > + struct ltdc_device *ldev = ddev->dev_private; > + > + DRM_DEBUG("%s\n", __func__); > + > + if (ldev->fbdev) { > + drm_fbdev_cma_fini(ldev->fbdev); > + ldev->fbdev = NULL; > + } > + drm_kms_helper_poll_fini(ddev); > + ltdc_unload(ddev); > + drm_mode_config_cleanup(ddev); > +} > + > +static int stm_drm_platform_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct drm_device *ddev; > + int ret; > + > + DRM_DEBUG("%s\n", __func__); > + > + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); > + > + ddev = drm_dev_alloc(&drv_driver, dev); > + if (IS_ERR(ddev)) > + return PTR_ERR(ddev); > + > + ret = drv_load(ddev); > + if (ret) > + goto err_unref; > + > + ret = drm_dev_register(ddev, 0); > + if (ret) > + goto err_unref; > + > + return 0; > + > +err_unref: > + drm_dev_unref(ddev); > + > + return ret; > +} > + > +static int stm_drm_platform_remove(struct platform_device *pdev) > +{ > + struct drm_device *ddev = platform_get_drvdata(pdev); > + > + DRM_DEBUG("%s\n", __func__); > + > + drm_dev_unregister(ddev); > + drv_unload(ddev); > + drm_dev_unref(ddev); > + > + return 0; > +} > + > +static const struct of_device_id drv_dt_ids[] = { > + { .compatible = "st,stm32-ltdc"}, > + { /* end node */ }, > +}; > +MODULE_DEVICE_TABLE(of, drv_dt_ids); > + > +static struct platform_driver stm_drm_platform_driver = { > + .probe = stm_drm_platform_probe, > + .remove = stm_drm_platform_remove, > + .driver = { > + .name = DRIVER_NAME, > + .of_match_table = drv_dt_ids, > + }, > +}; > + > +module_platform_driver(stm_drm_platform_driver); > + > +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/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c > new file mode 100644 > index 0000000..a373178 > --- /dev/null > +++ b/drivers/gpu/drm/stm/ltdc.c > @@ -0,0 +1,1161 @@ > +/* > + * 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