From mboxrd@z Thu Jan 1 00:00:00 1970 From: yannick.fertre@st.com (Yannick FERTRE) Date: Tue, 28 Mar 2017 09:34:52 +0000 Subject: [PATCH v4 2/8] drm/stm: Add STM32 LTDC driver In-Reply-To: <87shm61hah.fsf@eliezer.anholt.net> References: <1489597334-16896-1-git-send-email-yannick.fertre@st.com> <1489597334-16896-3-git-send-email-yannick.fertre@st.com> <87shm61hah.fsf@eliezer.anholt.net> Message-ID: <753050ba-668d-091c-ab75-1a8f9dceaac0@st.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi Eric, manu thanks for your help. These patches have been push on DRM misc. I solve all issues & I will push a new version today(V5). I create a patch on drm_gem_cma_helper.h regarding DEFINE_DRM_GEM_CMA_FOPS & a patch on drm_fb_cma_helper to add new function to get physical address. Best regards Yannick Fertr? On 03/21/2017 09:55 PM, Eric Anholt wrote: > Yannick Fertre writes: > >> 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. > > I've got some feedback inline that hopefully helps cut some boilerplate > DRM code. This looks like a complete driver, and some nice hardware as > far as modesetting goes. > > If you're planning on going through drm-misc, I'd do another pass at > review so I could give an Ack. > >> Change-Id: Ic1d6ade06ab7115c62e98dd21dc3981fb5948d1c >> Signed-off-by: Yannick Fertre >> --- >> drivers/gpu/drm/Kconfig | 3 +- >> drivers/gpu/drm/Makefile | 1 + >> drivers/gpu/drm/stm/Kconfig | 16 + >> drivers/gpu/drm/stm/Makefile | 7 + >> drivers/gpu/drm/stm/drv.c | 232 +++++++ >> drivers/gpu/drm/stm/drv.h | 22 + >> drivers/gpu/drm/stm/ltdc.c | 1422 ++++++++++++++++++++++++++++++++++++++++++ >> drivers/gpu/drm/stm/ltdc.h | 22 + >> 8 files changed, 1724 insertions(+), 1 deletion(-) >> 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/drv.h >> 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..dd5762a 100644 >> --- a/drivers/gpu/drm/Kconfig >> +++ b/drivers/gpu/drm/Kconfig >> @@ -203,7 +203,6 @@ config DRM_VGEM >> as used by Mesa's software renderer for enhanced performance. >> If M is selected the module will be called vgem. >> >> - >> source "drivers/gpu/drm/exynos/Kconfig" >> >> source "drivers/gpu/drm/rockchip/Kconfig" >> @@ -246,6 +245,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 59aae43..320fd86 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_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..8ef8a09 >> --- /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. > > Funny indentation here? Ok, Done > >> + 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..d5c46c5 >> --- /dev/null >> +++ b/drivers/gpu/drm/stm/drv.c >> @@ -0,0 +1,232 @@ >> +/* >> + * 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 "stm" >> +#define DRIVER_DESC "STMicroelectronics SoC DRM" >> +#define DRIVER_DATE "20170209" >> +#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 stm_private *priv = ddev->dev_private; >> + >> + drm_fbdev_cma_hotplug_event(priv->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 const struct file_operations drv_driver_fops = { >> + .owner = THIS_MODULE, >> + .open = drm_open, >> + .release = drm_release, >> + .unlocked_ioctl = drm_ioctl, >> + .compat_ioctl = drm_compat_ioctl, >> + .poll = drm_poll, >> + .read = drm_read, >> + .mmap = drm_gem_cma_mmap, >> + .get_unmapped_area = drm_gem_cma_get_unmapped_area, >> +}; > > This looks like almost a candidate for the new > DEFINE_DRM_GEM_CMA_FOPS(). Maybe that helper should conditionally add > the drm_gem_cma_get_unmapped_area reference on !MMU? Ok, Done I create a patch to add get_unmapped_area to the macro. > >> + >> +static void drv_lastclose(struct drm_device *ddev) >> +{ >> + struct stm_private *priv = ddev->dev_private; >> + >> + DRM_DEBUG("%s\n", __func__); >> + >> + drm_fbdev_cma_restore_mode(priv->fbdev); >> +} >> + >> +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 stm_private *priv; >> + int ret; >> + >> + DRM_DEBUG("%s\n", __func__); >> + >> + priv = devm_kzalloc(ddev->dev, sizeof(*priv), GFP_KERNEL); >> + if (!priv) >> + return -ENOMEM; >> + >> + ddev->dev_private = (void *)priv; >> + >> + 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) >> + return ret; >> + >> + drm_mode_config_reset(ddev); >> + drm_kms_helper_poll_init(ddev); >> + >> + if (ddev->mode_config.num_connector) { >> + priv = 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; >> + } >> + priv->fbdev = fbdev; >> + } >> + >> + platform_set_drvdata(pdev, priv); >> + >> + return 0; >> +} >> + >> +static void drv_unload(struct drm_device *ddev) >> +{ >> + struct stm_private *priv = ddev->dev_private; >> + >> + DRM_DEBUG("%s\n", __func__); >> + >> + ltdc_unload(ddev); >> + >> + if (priv->fbdev) { >> + drm_fbdev_cma_fini(priv->fbdev); >> + priv->fbdev = NULL; >> + } >> + >> + drm_kms_helper_poll_fini(ddev); >> + drm_vblank_cleanup(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/drv.h b/drivers/gpu/drm/stm/drv.h >> new file mode 100644 >> index 0000000..edff073 >> --- /dev/null >> +++ b/drivers/gpu/drm/stm/drv.h >> @@ -0,0 +1,22 @@ >> +/* >> + * 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 stm_private { >> + struct ltdc *ltdc; >> + struct drm_fbdev_cma *fbdev; >> +}; >> + > > Any reason not to just put the fbdev in ltdc and drop this struct? Ok. Done > >> +#endif >> diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c >> new file mode 100644 >> index 0000000..560375d >> --- /dev/null >> +++ b/drivers/gpu/drm/stm/ltdc.c >> @@ -0,0 +1,1422 @@ >> +/* >> + * 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