diff options
Diffstat (limited to 'drivers/gpu/drm/hisilicon')
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/Kconfig | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 238 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 123 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/Kconfig | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 359 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 258 | ||||
-rw-r--r-- | drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 48 |
15 files changed, 420 insertions, 725 deletions
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig index f20eedf0073a..dfc5aef62f7b 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig @@ -1,10 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_HISI_HIBMC tristate "DRM Support for Hisilicon Hibmc" - depends on DRM && PCI && MMU + depends on DRM && PCI && MMU && ARM64 select DRM_KMS_HELPER select DRM_VRAM_HELPER - + select DRM_TTM + select DRM_TTM_HELPER help Choose this option if you have a Hisilicon Hibmc soc chipset. If M is selected the module will be called hibmc-drm. diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile index 0c2d4296bccd..f99132715597 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_ttm.o obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c index 08657a3627f3..7fa7d4933f60 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c @@ -11,10 +11,16 @@ * Jianhua Li <lijianhua@huawei.com> */ +#include <linux/delay.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem_vram_helper.h> #include <drm/drm_plane_helper.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "hibmc_drm_drv.h" #include "hibmc_drm_regs.h" @@ -90,29 +96,19 @@ static void hibmc_plane_atomic_update(struct drm_plane *plane, { struct drm_plane_state *state = plane->state; u32 reg; - int ret; s64 gpu_addr = 0; unsigned int line_l; struct hibmc_drm_private *priv = plane->dev->dev_private; - struct hibmc_framebuffer *hibmc_fb; struct drm_gem_vram_object *gbo; if (!state->fb) return; - hibmc_fb = to_hibmc_framebuffer(state->fb); - gbo = drm_gem_vram_of_gem(hibmc_fb->obj); + gbo = drm_gem_vram_of_gem(state->fb->obj[0]); - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); - if (ret) { - DRM_ERROR("failed to pin bo: %d", ret); - return; - } gpu_addr = drm_gem_vram_offset(gbo); - if (gpu_addr < 0) { - drm_gem_vram_unpin(gbo); - return; - } + if (WARN_ON_ONCE(gpu_addr < 0)) + return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */ writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS); @@ -151,6 +147,8 @@ static struct drm_plane_funcs hibmc_plane_funcs = { }; static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = { + .prepare_fb = drm_gem_vram_plane_helper_prepare_fb, + .cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb, .atomic_check = hibmc_plane_atomic_check, .atomic_update = hibmc_plane_atomic_update, }; diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c index ce89e56937b0..4a8a4cfb4b75 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c @@ -13,17 +13,21 @@ #include <linux/console.h> #include <linux/module.h> +#include <linux/pci.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_gem_vram_helper.h> +#include <drm/drm_irq.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "hibmc_drm_drv.h" #include "hibmc_drm_regs.h" -static const struct file_operations hibmc_fops = { - .owner = THIS_MODULE, - DRM_VRAM_MM_FILE_OPERATIONS -}; +DEFINE_DRM_GEM_FOPS(hibmc_fops); static irqreturn_t hibmc_drm_interrupt(int irq, void *arg) { @@ -51,25 +55,23 @@ static struct drm_driver hibmc_driver = { .desc = "hibmc drm driver", .major = 1, .minor = 0, - .gem_free_object_unlocked = - drm_gem_vram_driver_gem_free_object_unlocked, + .debugfs_init = drm_vram_mm_debugfs_init, .dumb_create = hibmc_dumb_create, .dumb_map_offset = drm_gem_vram_driver_dumb_mmap_offset, + .gem_prime_mmap = drm_gem_prime_mmap, .irq_handler = hibmc_drm_interrupt, }; static int __maybe_unused hibmc_pm_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_get_drvdata(dev); return drm_mode_config_helper_suspend(drm_dev); } static int __maybe_unused hibmc_pm_resume(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_get_drvdata(dev); return drm_mode_config_helper_resume(drm_dev); } @@ -211,7 +213,7 @@ static int hibmc_hw_map(struct hibmc_drm_private *priv) ioaddr = pci_resource_start(pdev, 1); iosize = pci_resource_len(pdev, 1); - priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize); + priv->mmio = devm_ioremap(dev->dev, ioaddr, iosize); if (!priv->mmio) { DRM_ERROR("Cannot map mmio region\n"); return -ENOMEM; @@ -247,8 +249,6 @@ static int hibmc_unload(struct drm_device *dev) { struct hibmc_drm_private *priv = dev->dev_private; - hibmc_fbdev_fini(priv); - drm_atomic_helper_shutdown(dev); if (dev->irq_enabled) @@ -307,7 +307,7 @@ static int hibmc_load(struct drm_device *dev) /* reset all the states of crtc/plane/encoder/connector */ drm_mode_config_reset(dev); - ret = hibmc_fbdev_init(priv); + ret = drm_fbdev_generic_setup(dev, 16); if (ret) { DRM_ERROR("failed to initialize fbdev: %d\n", ret); goto err; @@ -388,18 +388,7 @@ static struct pci_driver hibmc_pci_driver = { .driver.pm = &hibmc_pm_ops, }; -static int __init hibmc_init(void) -{ - return pci_register_driver(&hibmc_pci_driver); -} - -static void __exit hibmc_exit(void) -{ - return pci_unregister_driver(&hibmc_pci_driver); -} - -module_init(hibmc_init); -module_exit(hibmc_exit); +module_pci_driver(hibmc_pci_driver); MODULE_DEVICE_TABLE(pci, hibmc_pci_table); MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>"); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h index 69348bf54a84..50a0c1f9d211 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h @@ -14,23 +14,10 @@ #ifndef HIBMC_DRM_DRV_H #define HIBMC_DRM_DRV_H -#include <drm/drmP.h> -#include <drm/drm_atomic.h> #include <drm/drm_fb_helper.h> -#include <drm/drm_gem.h> -#include <drm/drm_gem_vram_helper.h> -#include <drm/drm_vram_mm_helper.h> +#include <drm/drm_framebuffer.h> -struct hibmc_framebuffer { - struct drm_framebuffer fb; - struct drm_gem_object *obj; -}; - -struct hibmc_fbdev { - struct drm_fb_helper helper; /* must be first */ - struct hibmc_framebuffer *fb; - int size; -}; +struct drm_device; struct hibmc_drm_private { /* hw */ @@ -43,13 +30,8 @@ struct hibmc_drm_private { /* drm */ struct drm_device *dev; bool mode_config_initialized; - - /* fbdev */ - struct hibmc_fbdev *fbdev; }; -#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb) - void hibmc_set_power_mode(struct hibmc_drm_private *priv, unsigned int power_mode); void hibmc_set_current_gate(struct hibmc_drm_private *priv, @@ -57,15 +39,6 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv, int hibmc_de_init(struct hibmc_drm_private *priv); int hibmc_vdac_init(struct hibmc_drm_private *priv); -int hibmc_fbdev_init(struct hibmc_drm_private *priv); -void hibmc_fbdev_fini(struct hibmc_drm_private *priv); - -int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, - struct drm_gem_object **obj); -struct hibmc_framebuffer * -hibmc_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); int hibmc_mm_init(struct hibmc_drm_private *hibmc); void hibmc_mm_fini(struct hibmc_drm_private *hibmc); diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c deleted file mode 100644 index af1ea4cceffa..000000000000 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* Hisilicon Hibmc SoC drm driver - * - * Based on the bochs drm driver. - * - * Copyright (c) 2016 Huawei Limited. - * - * Author: - * Rongrong Zou <zourongrong@huawei.com> - * Rongrong Zou <zourongrong@gmail.com> - * Jianhua Li <lijianhua@huawei.com> - */ - -#include <drm/drm_crtc.h> -#include <drm/drm_fb_helper.h> -#include <drm/drm_probe_helper.h> - -#include "hibmc_drm_drv.h" - -static int hibmcfb_create_object( - struct hibmc_drm_private *priv, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object **gobj_p) -{ - struct drm_gem_object *gobj; - struct drm_device *dev = priv->dev; - u32 size; - int ret = 0; - - size = mode_cmd->pitches[0] * mode_cmd->height; - ret = hibmc_gem_create(dev, size, true, &gobj); - if (ret) - return ret; - - *gobj_p = gobj; - return ret; -} - -static struct fb_ops hibmc_drm_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = drm_fb_helper_sys_fillrect, - .fb_copyarea = drm_fb_helper_sys_copyarea, - .fb_imageblit = drm_fb_helper_sys_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, -}; - -static int hibmc_drm_fb_create(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct hibmc_fbdev *hi_fbdev = - container_of(helper, struct hibmc_fbdev, helper); - struct hibmc_drm_private *priv = helper->dev->dev_private; - struct fb_info *info; - struct drm_mode_fb_cmd2 mode_cmd; - struct drm_gem_object *gobj = NULL; - int ret = 0; - size_t size; - unsigned int bytes_per_pixel; - struct drm_gem_vram_object *gbo = NULL; - void *base; - - DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", - sizes->surface_width, sizes->surface_height, - sizes->surface_bpp); - - bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel; - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height); - - ret = hibmcfb_create_object(priv, &mode_cmd, &gobj); - if (ret) { - DRM_ERROR("failed to create fbcon backing object: %d\n", ret); - return -ENOMEM; - } - - gbo = drm_gem_vram_of_gem(gobj); - - ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM); - if (ret) { - DRM_ERROR("failed to pin fbcon: %d\n", ret); - goto out_unref_gem; - } - - base = drm_gem_vram_kmap(gbo, true, NULL); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - DRM_ERROR("failed to kmap fbcon: %d\n", ret); - goto out_unpin_bo; - } - - info = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - DRM_ERROR("failed to allocate fbi: %d\n", ret); - goto out_release_fbi; - } - - hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj); - if (IS_ERR(hi_fbdev->fb)) { - ret = PTR_ERR(hi_fbdev->fb); - hi_fbdev->fb = NULL; - DRM_ERROR("failed to initialize framebuffer: %d\n", ret); - goto out_release_fbi; - } - - priv->fbdev->size = size; - hi_fbdev->helper.fb = &hi_fbdev->fb->fb; - - info->fbops = &hibmc_drm_fb_ops; - - drm_fb_helper_fill_info(info, &priv->fbdev->helper, sizes); - - info->screen_base = base; - info->screen_size = size; - - info->fix.smem_start = gbo->bo.mem.bus.offset + gbo->bo.mem.bus.base; - info->fix.smem_len = size; - return 0; - -out_release_fbi: - drm_gem_vram_kunmap(gbo); -out_unpin_bo: - drm_gem_vram_unpin(gbo); -out_unref_gem: - drm_gem_object_put_unlocked(gobj); - - return ret; -} - -static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev) -{ - struct hibmc_framebuffer *gfb = fbdev->fb; - struct drm_fb_helper *fbh = &fbdev->helper; - - drm_fb_helper_unregister_fbi(fbh); - - drm_fb_helper_fini(fbh); - - if (gfb) - drm_framebuffer_put(&gfb->fb); -} - -static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = { - .fb_probe = hibmc_drm_fb_create, -}; - -int hibmc_fbdev_init(struct hibmc_drm_private *priv) -{ - int ret; - struct fb_var_screeninfo *var; - struct fb_fix_screeninfo *fix; - struct hibmc_fbdev *hifbdev; - - hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL); - if (!hifbdev) { - DRM_ERROR("failed to allocate hibmc_fbdev\n"); - return -ENOMEM; - } - - priv->fbdev = hifbdev; - drm_fb_helper_prepare(priv->dev, &hifbdev->helper, - &hibmc_fbdev_helper_funcs); - - /* Now just one crtc and one channel */ - ret = drm_fb_helper_init(priv->dev, &hifbdev->helper, 1); - if (ret) { - DRM_ERROR("failed to initialize fb helper: %d\n", ret); - return ret; - } - - ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper); - if (ret) { - DRM_ERROR("failed to add all connectors: %d\n", ret); - goto fini; - } - - ret = drm_fb_helper_initial_config(&hifbdev->helper, 16); - if (ret) { - DRM_ERROR("failed to setup initial conn config: %d\n", ret); - goto fini; - } - - var = &hifbdev->helper.fbdev->var; - fix = &hifbdev->helper.fbdev->fix; - - DRM_DEBUG_DRIVER("Member of info->var is :\n" - "xres=%d\n" - "yres=%d\n" - "xres_virtual=%d\n" - "yres_virtual=%d\n" - "xoffset=%d\n" - "yoffset=%d\n" - "bits_per_pixel=%d\n" - "...\n", var->xres, var->yres, var->xres_virtual, - var->yres_virtual, var->xoffset, var->yoffset, - var->bits_per_pixel); - DRM_DEBUG_DRIVER("Member of info->fix is :\n" - "smem_start=%lx\n" - "smem_len=%d\n" - "type=%d\n" - "type_aux=%d\n" - "visual=%d\n" - "xpanstep=%d\n" - "ypanstep=%d\n" - "ywrapstep=%d\n" - "line_length=%d\n" - "accel=%d\n" - "capabilities=%d\n" - "...\n", fix->smem_start, fix->smem_len, fix->type, - fix->type_aux, fix->visual, fix->xpanstep, - fix->ypanstep, fix->ywrapstep, fix->line_length, - fix->accel, fix->capabilities); - - return 0; - -fini: - drm_fb_helper_fini(&hifbdev->helper); - return ret; -} - -void hibmc_fbdev_fini(struct hibmc_drm_private *priv) -{ - if (!priv->fbdev) - return; - - hibmc_fbdev_destroy(priv->fbdev); - priv->fbdev = NULL; -} diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c index 634a3bf018b2..6d98fdc06f6c 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c @@ -13,6 +13,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_print.h> #include "hibmc_drm_drv.h" #include "hibmc_drm_regs.h" diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c index 5d4a03cd7d50..50b988fdd5cc 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c @@ -11,7 +11,13 @@ * Jianhua Li <lijianhua@huawei.com> */ +#include <linux/pci.h> + #include <drm/drm_atomic_helper.h> +#include <drm/drm_gem.h> +#include <drm/drm_gem_framebuffer_helper.h> +#include <drm/drm_gem_vram_helper.h> +#include <drm/drm_print.h> #include "hibmc_drm_drv.h" @@ -23,7 +29,7 @@ int hibmc_mm_init(struct hibmc_drm_private *hibmc) vmm = drm_vram_helper_alloc_mm(dev, pci_resource_start(dev->pdev, 0), - hibmc->fb_size, &drm_gem_vram_mm_funcs); + hibmc->fb_size); if (IS_ERR(vmm)) { ret = PTR_ERR(vmm); DRM_ERROR("Error initializing VRAM MM; %d\n", ret); @@ -41,125 +47,14 @@ void hibmc_mm_fini(struct hibmc_drm_private *hibmc) drm_vram_helper_release_mm(hibmc->dev); } -int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel, - struct drm_gem_object **obj) -{ - struct drm_gem_vram_object *gbo; - int ret; - - *obj = NULL; - - size = roundup(size, PAGE_SIZE); - if (size == 0) - return -EINVAL; - - gbo = drm_gem_vram_create(dev, &dev->vram_mm->bdev, size, 0, false); - if (IS_ERR(gbo)) { - ret = PTR_ERR(gbo); - if (ret != -ERESTARTSYS) - DRM_ERROR("failed to allocate GEM object: %d\n", ret); - return ret; - } - *obj = &gbo->gem; - return 0; -} - int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { - struct drm_gem_object *gobj; - u32 handle; - int ret; - - args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16); - args->size = args->pitch * args->height; - - ret = hibmc_gem_create(dev, args->size, false, - &gobj); - if (ret) { - DRM_ERROR("failed to create GEM object: %d\n", ret); - return ret; - } - - ret = drm_gem_handle_create(file, gobj, &handle); - drm_gem_object_put_unlocked(gobj); - if (ret) { - DRM_ERROR("failed to unreference GEM object: %d\n", ret); - return ret; - } - - args->handle = handle; - return 0; -} - -static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb) -{ - struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb); - - drm_gem_object_put_unlocked(hibmc_fb->obj); - drm_framebuffer_cleanup(fb); - kfree(hibmc_fb); -} - -static const struct drm_framebuffer_funcs hibmc_fb_funcs = { - .destroy = hibmc_user_framebuffer_destroy, -}; - -struct hibmc_framebuffer * -hibmc_framebuffer_init(struct drm_device *dev, - const struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) -{ - struct hibmc_framebuffer *hibmc_fb; - int ret; - - hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL); - if (!hibmc_fb) { - DRM_ERROR("failed to allocate hibmc_fb\n"); - return ERR_PTR(-ENOMEM); - } - - drm_helper_mode_fill_fb_struct(dev, &hibmc_fb->fb, mode_cmd); - hibmc_fb->obj = obj; - ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs); - if (ret) { - DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); - kfree(hibmc_fb); - return ERR_PTR(ret); - } - - return hibmc_fb; -} - -static struct drm_framebuffer * -hibmc_user_framebuffer_create(struct drm_device *dev, - struct drm_file *filp, - const struct drm_mode_fb_cmd2 *mode_cmd) -{ - struct drm_gem_object *obj; - struct hibmc_framebuffer *hibmc_fb; - - DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n", - mode_cmd->width, mode_cmd->height, - (mode_cmd->pixel_format) & 0xff, - (mode_cmd->pixel_format >> 8) & 0xff, - (mode_cmd->pixel_format >> 16) & 0xff, - (mode_cmd->pixel_format >> 24) & 0xff); - - obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]); - if (!obj) - return ERR_PTR(-ENOENT); - - hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj); - if (IS_ERR(hibmc_fb)) { - drm_gem_object_put_unlocked(obj); - return ERR_PTR((long)hibmc_fb); - } - return &hibmc_fb->fb; + return drm_gem_vram_fill_create_dumb(file, dev, 0, 16, args); } const struct drm_mode_config_funcs hibmc_mode_funcs = { .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, - .fb_create = hibmc_user_framebuffer_create, + .fb_create = drm_gem_fb_create, }; diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig index 0fa29af08ad0..290553e2f6b4 100644 --- a/drivers/gpu/drm/hisilicon/kirin/Kconfig +++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig @@ -5,16 +5,8 @@ config DRM_HISI_KIRIN select DRM_KMS_HELPER select DRM_GEM_CMA_HELPER select DRM_KMS_CMA_HELPER - select HISI_KIRIN_DW_DSI + select DRM_MIPI_DSI help Choose this option if you have a hisilicon Kirin chipsets(hi6220). If M is selected the module will be called kirin-drm. -config HISI_KIRIN_DW_DSI - tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI" - depends on DRM_HISI_KIRIN - select DRM_MIPI_DSI - help - This selects support for HiSilicon Kirin SoC specific extensions for - the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on - hi6220 based SoC, you should selet this option. diff --git a/drivers/gpu/drm/hisilicon/kirin/Makefile b/drivers/gpu/drm/hisilicon/kirin/Makefile index c0501fa3fe53..d9323f66a7d4 100644 --- a/drivers/gpu/drm/hisilicon/kirin/Makefile +++ b/drivers/gpu/drm/hisilicon/kirin/Makefile @@ -2,6 +2,5 @@ kirin-drm-y := kirin_drm_drv.o \ kirin_drm_ade.o -obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o +obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o dw_drm_dsi.o -obj-$(CONFIG_HISI_KIRIN_DW_DSI) += dw_drm_dsi.o diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c index 5bf8138941de..bdcf9c6ae9e9 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -18,6 +18,7 @@ #include <linux/platform_device.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> #include <drm/drm_device.h> #include <drm/drm_encoder_slave.h> #include <drm/drm_mipi_dsi.h> diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h index e2ac09894a6d..0da860200410 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h @@ -83,6 +83,7 @@ #define VSIZE_OFST 20 #define LDI_INT_EN 0x741C #define FRAME_END_INT_EN_OFST 1 +#define UNDERFLOW_INT_EN_OFST 2 #define LDI_CTRL 0x7420 #define BPP_OFST 3 #define DATA_GATE_EN BIT(2) diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c index ad7042ae2241..73cd28a6ea07 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c @@ -13,32 +13,31 @@ #include <linux/bitops.h> #include <linux/clk.h> -#include <video/display_timing.h> #include <linux/mfd/syscon.h> +#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/reset.h> -#include <drm/drmP.h> +#include <video/display_timing.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> +#include <drm/drm_fourcc.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_plane_helper.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> +#include <drm/drm_gem_framebuffer_helper.h> #include "kirin_drm_drv.h" #include "kirin_ade_reg.h" -#define PRIMARY_CH ADE_CH1 /* primary plane */ #define OUT_OVLY ADE_OVLY2 /* output overlay compositor */ #define ADE_DEBUG 1 -#define to_ade_crtc(crtc) \ - container_of(crtc, struct ade_crtc, base) - -#define to_ade_plane(plane) \ - container_of(plane, struct ade_plane, base) struct ade_hw_ctx { void __iomem *base; @@ -47,36 +46,14 @@ struct ade_hw_ctx { struct clk *media_noc_clk; struct clk *ade_pix_clk; struct reset_control *reset; + struct work_struct display_reset_wq; bool power_on; int irq; -}; - -struct ade_crtc { - struct drm_crtc base; - struct ade_hw_ctx *ctx; - bool enable; - u32 out_format; -}; - -struct ade_plane { - struct drm_plane base; - void *ctx; - u8 ch; /* channel */ -}; - -struct ade_data { - struct ade_crtc acrtc; - struct ade_plane aplane[ADE_CH_NUM]; - struct ade_hw_ctx ctx; -}; -/* ade-format info: */ -struct ade_format { - u32 pixel_format; - enum ade_fb_format ade_format; + struct drm_crtc *crtc; }; -static const struct ade_format ade_formats[] = { +static const struct kirin_format ade_formats[] = { /* 16bpp RGB: */ { DRM_FORMAT_RGB565, ADE_RGB_565 }, { DRM_FORMAT_BGR565, ADE_BGR_565 }, @@ -92,7 +69,7 @@ static const struct ade_format ade_formats[] = { { DRM_FORMAT_ABGR8888, ADE_ABGR_8888 }, }; -static const u32 channel_formats1[] = { +static const u32 channel_formats[] = { /* channel 1,2,3,4 */ DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888, DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, @@ -100,19 +77,6 @@ static const u32 channel_formats1[] = { DRM_FORMAT_ABGR8888 }; -u32 ade_get_channel_formats(u8 ch, const u32 **formats) -{ - switch (ch) { - case ADE_CH1: - *formats = channel_formats1; - return ARRAY_SIZE(channel_formats1); - default: - DRM_ERROR("no this channel %d\n", ch); - *formats = NULL; - return 0; - } -} - /* convert from fourcc format to ade format */ static u32 ade_get_format(u32 pixel_format) { @@ -120,7 +84,7 @@ static u32 ade_get_format(u32 pixel_format) for (i = 0; i < ARRAY_SIZE(ade_formats); i++) if (ade_formats[i].pixel_format == pixel_format) - return ade_formats[i].ade_format; + return ade_formats[i].hw_format; /* not found */ DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", @@ -172,14 +136,15 @@ static void ade_init(struct ade_hw_ctx *ctx) */ ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST, FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND); + ade_update_bits(base + LDI_INT_EN, UNDERFLOW_INT_EN_OFST, MASK(1), 1); } static bool ade_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; adjusted_mode->clock = clk_round_rate(ctx->ade_pix_clk, mode->clock * 1000) / 1000; @@ -204,11 +169,10 @@ static void ade_set_pix_clk(struct ade_hw_ctx *ctx, adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000; } -static void ade_ldi_set_mode(struct ade_crtc *acrtc, +static void ade_ldi_set_mode(struct ade_hw_ctx *ctx, struct drm_display_mode *mode, struct drm_display_mode *adj_mode) { - struct ade_hw_ctx *ctx = acrtc->ctx; void __iomem *base = ctx->base; u32 width = mode->hdisplay; u32 height = mode->vdisplay; @@ -295,9 +259,8 @@ static void ade_power_down(struct ade_hw_ctx *ctx) ctx->power_on = false; } -static void ade_set_medianoc_qos(struct ade_crtc *acrtc) +static void ade_set_medianoc_qos(struct ade_hw_ctx *ctx) { - struct ade_hw_ctx *ctx = acrtc->ctx; struct regmap *map = ctx->noc_regmap; regmap_update_bits(map, ADE0_QOSGENERATOR_MODE, @@ -313,8 +276,8 @@ static void ade_set_medianoc_qos(struct ade_crtc *acrtc) static int ade_crtc_enable_vblank(struct drm_crtc *crtc) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; void __iomem *base = ctx->base; if (!ctx->power_on) @@ -328,8 +291,8 @@ static int ade_crtc_enable_vblank(struct drm_crtc *crtc) static void ade_crtc_disable_vblank(struct drm_crtc *crtc) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; void __iomem *base = ctx->base; if (!ctx->power_on) { @@ -341,11 +304,21 @@ static void ade_crtc_disable_vblank(struct drm_crtc *crtc) MASK(1), 0); } +static void drm_underflow_wq(struct work_struct *work) +{ + struct ade_hw_ctx *ctx = container_of(work, struct ade_hw_ctx, + display_reset_wq); + struct drm_device *drm_dev = ctx->crtc->dev; + struct drm_atomic_state *state; + + state = drm_atomic_helper_suspend(drm_dev); + drm_atomic_helper_resume(drm_dev, state); +} + static irqreturn_t ade_irq_handler(int irq, void *data) { - struct ade_crtc *acrtc = data; - struct ade_hw_ctx *ctx = acrtc->ctx; - struct drm_crtc *crtc = &acrtc->base; + struct ade_hw_ctx *ctx = data; + struct drm_crtc *crtc = ctx->crtc; void __iomem *base = ctx->base; u32 status; @@ -358,15 +331,20 @@ static irqreturn_t ade_irq_handler(int irq, void *data) MASK(1), 1); drm_crtc_handle_vblank(crtc); } + if (status & BIT(UNDERFLOW_INT_EN_OFST)) { + ade_update_bits(base + LDI_INT_CLR, UNDERFLOW_INT_EN_OFST, + MASK(1), 1); + DRM_ERROR("LDI underflow!"); + schedule_work(&ctx->display_reset_wq); + } return IRQ_HANDLED; } -static void ade_display_enable(struct ade_crtc *acrtc) +static void ade_display_enable(struct ade_hw_ctx *ctx) { - struct ade_hw_ctx *ctx = acrtc->ctx; void __iomem *base = ctx->base; - u32 out_fmt = acrtc->out_format; + u32 out_fmt = LDI_OUT_RGB_888; /* enable output overlay compositor */ writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY)); @@ -479,11 +457,11 @@ static void ade_dump_regs(void __iomem *base) { } static void ade_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; int ret; - if (acrtc->enable) + if (kcrtc->enable) return; if (!ctx->power_on) { @@ -492,63 +470,63 @@ static void ade_crtc_atomic_enable(struct drm_crtc *crtc, return; } - ade_set_medianoc_qos(acrtc); - ade_display_enable(acrtc); + ade_set_medianoc_qos(ctx); + ade_display_enable(ctx); ade_dump_regs(ctx->base); drm_crtc_vblank_on(crtc); - acrtc->enable = true; + kcrtc->enable = true; } static void ade_crtc_atomic_disable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; - if (!acrtc->enable) + if (!kcrtc->enable) return; drm_crtc_vblank_off(crtc); ade_power_down(ctx); - acrtc->enable = false; + kcrtc->enable = false; } static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; struct drm_display_mode *mode = &crtc->state->mode; struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; if (!ctx->power_on) (void)ade_power_up(ctx); - ade_ldi_set_mode(acrtc, mode, adj_mode); + ade_ldi_set_mode(ctx, mode, adj_mode); } static void ade_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; struct drm_display_mode *mode = &crtc->state->mode; struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode; if (!ctx->power_on) (void)ade_power_up(ctx); - ade_ldi_set_mode(acrtc, mode, adj_mode); + ade_ldi_set_mode(ctx, mode, adj_mode); } static void ade_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { - struct ade_crtc *acrtc = to_ade_crtc(crtc); - struct ade_hw_ctx *ctx = acrtc->ctx; + struct kirin_crtc *kcrtc = to_kirin_crtc(crtc); + struct ade_hw_ctx *ctx = kcrtc->hw_ctx; struct drm_pending_vblank_event *event = crtc->state->event; void __iomem *base = ctx->base; /* only crtc is enabled regs take effect */ - if (acrtc->enable) { + if (kcrtc->enable) { ade_dump_regs(base); /* flush ade registers */ writel(ADE_ENABLE, base + ADE_EN); @@ -586,35 +564,6 @@ static const struct drm_crtc_funcs ade_crtc_funcs = { .disable_vblank = ade_crtc_disable_vblank, }; -static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, - struct drm_plane *plane) -{ - struct device_node *port; - int ret; - - /* set crtc port so that - * drm_of_find_possible_crtcs call works - */ - port = of_get_child_by_name(dev->dev->of_node, "port"); - if (!port) { - DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node); - return -EINVAL; - } - of_node_put(port); - crtc->port = port; - - ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, - &ade_crtc_funcs, NULL); - if (ret) { - DRM_ERROR("failed to init crtc.\n"); - return ret; - } - - drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs); - - return 0; -} - static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb, u32 ch, u32 y, u32 in_h, u32 fmt) { @@ -776,16 +725,16 @@ static void ade_compositor_routing_disable(void __iomem *base, u32 ch) /* * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor */ -static void ade_update_channel(struct ade_plane *aplane, +static void ade_update_channel(struct kirin_plane *kplane, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, u32 src_x, u32 src_y, u32 src_w, u32 src_h) { - struct ade_hw_ctx *ctx = aplane->ctx; + struct ade_hw_ctx *ctx = kplane->hw_ctx; void __iomem *base = ctx->base; u32 fmt = ade_get_format(fb->format->format); - u32 ch = aplane->ch; + u32 ch = kplane->ch; u32 in_w; u32 in_h; @@ -809,11 +758,11 @@ static void ade_update_channel(struct ade_plane *aplane, ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt); } -static void ade_disable_channel(struct ade_plane *aplane) +static void ade_disable_channel(struct kirin_plane *kplane) { - struct ade_hw_ctx *ctx = aplane->ctx; + struct ade_hw_ctx *ctx = kplane->hw_ctx; void __iomem *base = ctx->base; - u32 ch = aplane->ch; + u32 ch = kplane->ch; DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1); @@ -875,10 +824,10 @@ static int ade_plane_atomic_check(struct drm_plane *plane, static void ade_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct drm_plane_state *state = plane->state; - struct ade_plane *aplane = to_ade_plane(plane); + struct drm_plane_state *state = plane->state; + struct kirin_plane *kplane = to_kirin_plane(plane); - ade_update_channel(aplane, state->fb, state->crtc_x, state->crtc_y, + ade_update_channel(kplane, state->fb, state->crtc_x, state->crtc_y, state->crtc_w, state->crtc_h, state->src_x >> 16, state->src_y >> 16, state->src_w >> 16, state->src_h >> 16); @@ -887,9 +836,9 @@ static void ade_plane_atomic_update(struct drm_plane *plane, static void ade_plane_atomic_disable(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct ade_plane *aplane = to_ade_plane(plane); + struct kirin_plane *kplane = to_kirin_plane(plane); - ade_disable_channel(aplane); + ade_disable_channel(kplane); } static const struct drm_plane_helper_funcs ade_plane_helper_funcs = { @@ -907,144 +856,124 @@ static struct drm_plane_funcs ade_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; -static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane, - enum drm_plane_type type) -{ - const u32 *fmts; - u32 fmts_cnt; - int ret = 0; - - /* get properties */ - fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts); - if (ret) - return ret; - - ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs, - fmts, fmts_cnt, NULL, type, NULL); - if (ret) { - DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch); - return ret; - } - - drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs); - - return 0; -} - -static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx) +static void *ade_hw_ctx_alloc(struct platform_device *pdev, + struct drm_crtc *crtc) { struct resource *res; struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; + struct ade_hw_ctx *ctx = NULL; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + DRM_ERROR("failed to alloc ade_hw_ctx\n"); + return ERR_PTR(-ENOMEM); + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ctx->base = devm_ioremap_resource(dev, res); if (IS_ERR(ctx->base)) { DRM_ERROR("failed to remap ade io base\n"); - return PTR_ERR(ctx->base); + return ERR_PTR(-EIO); } ctx->reset = devm_reset_control_get(dev, NULL); if (IS_ERR(ctx->reset)) - return PTR_ERR(ctx->reset); + return ERR_PTR(-ENODEV); ctx->noc_regmap = syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon"); if (IS_ERR(ctx->noc_regmap)) { DRM_ERROR("failed to get noc regmap\n"); - return PTR_ERR(ctx->noc_regmap); + return ERR_PTR(-ENODEV); } ctx->irq = platform_get_irq(pdev, 0); if (ctx->irq < 0) { DRM_ERROR("failed to get irq\n"); - return -ENODEV; + return ERR_PTR(-ENODEV); } ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core"); if (IS_ERR(ctx->ade_core_clk)) { DRM_ERROR("failed to parse clk ADE_CORE\n"); - return PTR_ERR(ctx->ade_core_clk); + return ERR_PTR(-ENODEV); } ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg"); if (IS_ERR(ctx->media_noc_clk)) { DRM_ERROR("failed to parse clk CODEC_JPEG\n"); - return PTR_ERR(ctx->media_noc_clk); + return ERR_PTR(-ENODEV); } ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix"); if (IS_ERR(ctx->ade_pix_clk)) { DRM_ERROR("failed to parse clk ADE_PIX\n"); - return PTR_ERR(ctx->ade_pix_clk); - } - - return 0; -} - -static int ade_drm_init(struct platform_device *pdev) -{ - struct drm_device *dev = platform_get_drvdata(pdev); - struct ade_data *ade; - struct ade_hw_ctx *ctx; - struct ade_crtc *acrtc; - struct ade_plane *aplane; - enum drm_plane_type type; - int ret; - int i; - - ade = devm_kzalloc(dev->dev, sizeof(*ade), GFP_KERNEL); - if (!ade) { - DRM_ERROR("failed to alloc ade_data\n"); - return -ENOMEM; - } - platform_set_drvdata(pdev, ade); - - ctx = &ade->ctx; - acrtc = &ade->acrtc; - acrtc->ctx = ctx; - acrtc->out_format = LDI_OUT_RGB_888; - - ret = ade_dts_parse(pdev, ctx); - if (ret) - return ret; - - /* - * plane init - * TODO: Now only support primary plane, overlay planes - * need to do. - */ - for (i = 0; i < ADE_CH_NUM; i++) { - aplane = &ade->aplane[i]; - aplane->ch = i; - aplane->ctx = ctx; - type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY : - DRM_PLANE_TYPE_OVERLAY; - - ret = ade_plane_init(dev, aplane, type); - if (ret) - return ret; + return ERR_PTR(-ENODEV); } - /* crtc init */ - ret = ade_crtc_init(dev, &acrtc->base, &ade->aplane[PRIMARY_CH].base); - if (ret) - return ret; - /* vblank irq init */ - ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler, - IRQF_SHARED, dev->driver->name, acrtc); + ret = devm_request_irq(dev, ctx->irq, ade_irq_handler, + IRQF_SHARED, dev->driver->name, ctx); if (ret) - return ret; + return ERR_PTR(-EIO); - return 0; + INIT_WORK(&ctx->display_reset_wq, drm_underflow_wq); + ctx->crtc = crtc; + + return ctx; } -static void ade_drm_cleanup(struct platform_device *pdev) +static void ade_hw_ctx_cleanup(void *hw_ctx) { } -const struct kirin_dc_ops ade_dc_ops = { - .init = ade_drm_init, - .cleanup = ade_drm_cleanup +static const struct drm_mode_config_funcs ade_mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, + +}; + +DEFINE_DRM_GEM_CMA_FOPS(ade_fops); + +static struct drm_driver ade_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .fops = &ade_fops, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create_internal, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .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 = "kirin", + .desc = "Hisilicon Kirin620 SoC DRM Driver", + .date = "20150718", + .major = 1, + .minor = 0, +}; + +struct kirin_drm_data ade_driver_data = { + .register_connects = false, + .num_planes = ADE_CH_NUM, + .prim_plane = ADE_CH1, + .channel_formats = channel_formats, + .channel_formats_cnt = ARRAY_SIZE(channel_formats), + .config_max_width = 2048, + .config_max_height = 2048, + .driver = &ade_driver, + .crtc_helper_funcs = &ade_crtc_helper_funcs, + .crtc_funcs = &ade_crtc_funcs, + .plane_helper_funcs = &ade_plane_helper_funcs, + .plane_funcs = &ade_plane_funcs, + .mode_config_funcs = &ade_mode_config_funcs, + + .alloc_hw_ctx = ade_hw_ctx_alloc, + .cleanup_hw_ctx = ade_hw_ctx_cleanup, }; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c index 4a7fe10a37cb..d3145ae877d7 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c @@ -13,59 +13,162 @@ #include <linux/of_platform.h> #include <linux/component.h> +#include <linux/module.h> #include <linux/of_graph.h> +#include <linux/platform_device.h> -#include <drm/drmP.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> +#include <drm/drm_vblank.h> #include "kirin_drm_drv.h" -static struct kirin_dc_ops *dc_ops; +#define KIRIN_MAX_PLANE 2 -static int kirin_drm_kms_cleanup(struct drm_device *dev) +struct kirin_drm_private { + struct kirin_crtc crtc; + struct kirin_plane planes[KIRIN_MAX_PLANE]; + void *hw_ctx; +}; + +static int kirin_drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_plane *plane, + const struct kirin_drm_data *driver_data) { - drm_kms_helper_poll_fini(dev); - dc_ops->cleanup(to_platform_device(dev->dev)); - drm_mode_config_cleanup(dev); + struct device_node *port; + int ret; + + /* set crtc port so that + * drm_of_find_possible_crtcs call works + */ + port = of_get_child_by_name(dev->dev->of_node, "port"); + if (!port) { + DRM_ERROR("no port node found in %pOF\n", dev->dev->of_node); + return -EINVAL; + } + of_node_put(port); + crtc->port = port; + + ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, + driver_data->crtc_funcs, NULL); + if (ret) { + DRM_ERROR("failed to init crtc.\n"); + return ret; + } + + drm_crtc_helper_add(crtc, driver_data->crtc_helper_funcs); return 0; } -static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = { - .fb_create = drm_gem_fb_create, - .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, -}; +static int kirin_drm_plane_init(struct drm_device *dev, struct drm_plane *plane, + enum drm_plane_type type, + const struct kirin_drm_data *data) +{ + int ret = 0; + + ret = drm_universal_plane_init(dev, plane, 1, data->plane_funcs, + data->channel_formats, + data->channel_formats_cnt, + NULL, type, NULL); + if (ret) { + DRM_ERROR("fail to init plane, ch=%d\n", 0); + return ret; + } + + drm_plane_helper_add(plane, data->plane_helper_funcs); -static void kirin_drm_mode_config_init(struct drm_device *dev) + return 0; +} + +static void kirin_drm_private_cleanup(struct drm_device *dev) { - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; + struct kirin_drm_private *kirin_priv = dev->dev_private; + struct kirin_drm_data *data; - dev->mode_config.max_width = 2048; - dev->mode_config.max_height = 2048; + data = (struct kirin_drm_data *)of_device_get_match_data(dev->dev); + if (data->cleanup_hw_ctx) + data->cleanup_hw_ctx(kirin_priv->hw_ctx); - dev->mode_config.funcs = &kirin_drm_mode_config_funcs; + devm_kfree(dev->dev, kirin_priv); + dev->dev_private = NULL; } -static int kirin_drm_kms_init(struct drm_device *dev) +static int kirin_drm_private_init(struct drm_device *dev, + const struct kirin_drm_data *driver_data) { + struct platform_device *pdev = to_platform_device(dev->dev); + struct kirin_drm_private *kirin_priv; + struct drm_plane *prim_plane; + enum drm_plane_type type; + void *ctx; int ret; + u32 ch; + + kirin_priv = devm_kzalloc(dev->dev, sizeof(*kirin_priv), GFP_KERNEL); + if (!kirin_priv) { + DRM_ERROR("failed to alloc kirin_drm_private\n"); + return -ENOMEM; + } + + ctx = driver_data->alloc_hw_ctx(pdev, &kirin_priv->crtc.base); + if (IS_ERR(ctx)) { + DRM_ERROR("failed to initialize kirin_priv hw ctx\n"); + return -EINVAL; + } + kirin_priv->hw_ctx = ctx; + + /* + * plane init + * TODO: Now only support primary plane, overlay planes + * need to do. + */ + for (ch = 0; ch < driver_data->num_planes; ch++) { + if (ch == driver_data->prim_plane) + type = DRM_PLANE_TYPE_PRIMARY; + else + type = DRM_PLANE_TYPE_OVERLAY; + ret = kirin_drm_plane_init(dev, &kirin_priv->planes[ch].base, + type, driver_data); + if (ret) + return ret; + kirin_priv->planes[ch].ch = ch; + kirin_priv->planes[ch].hw_ctx = ctx; + } - dev_set_drvdata(dev->dev, dev); + /* crtc init */ + prim_plane = &kirin_priv->planes[driver_data->prim_plane].base; + ret = kirin_drm_crtc_init(dev, &kirin_priv->crtc.base, + prim_plane, driver_data); + if (ret) + return ret; + kirin_priv->crtc.hw_ctx = ctx; + dev->dev_private = kirin_priv; + + return 0; +} + +static int kirin_drm_kms_init(struct drm_device *dev, + const struct kirin_drm_data *driver_data) +{ + int ret; /* dev->mode_config initialization */ drm_mode_config_init(dev); - kirin_drm_mode_config_init(dev); + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + dev->mode_config.max_width = driver_data->config_max_width; + dev->mode_config.max_height = driver_data->config_max_width; + dev->mode_config.funcs = driver_data->mode_config_funcs; /* display controller init */ - ret = dc_ops->init(to_platform_device(dev->dev)); + ret = kirin_drm_private_init(dev, driver_data); if (ret) goto err_mode_config_cleanup; @@ -73,7 +176,7 @@ static int kirin_drm_kms_init(struct drm_device *dev) ret = component_bind_all(dev->dev, dev); if (ret) { DRM_ERROR("failed to bind all component.\n"); - goto err_dc_cleanup; + goto err_private_cleanup; } /* vblank init */ @@ -95,65 +198,78 @@ static int kirin_drm_kms_init(struct drm_device *dev) err_unbind_all: component_unbind_all(dev->dev, dev); -err_dc_cleanup: - dc_ops->cleanup(to_platform_device(dev->dev)); +err_private_cleanup: + kirin_drm_private_cleanup(dev); err_mode_config_cleanup: drm_mode_config_cleanup(dev); - return ret; } -DEFINE_DRM_GEM_CMA_FOPS(kirin_drm_fops); - -static int kirin_gem_cma_dumb_create(struct drm_file *file, - struct drm_device *dev, - struct drm_mode_create_dumb *args) +static int compare_of(struct device *dev, void *data) { - return drm_gem_cma_dumb_create_internal(file, dev, args); + return dev->of_node == data; } -static struct drm_driver kirin_drm_driver = { - .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | - DRIVER_ATOMIC, - .fops = &kirin_drm_fops, - - .gem_free_object_unlocked = drm_gem_cma_free_object, - .gem_vm_ops = &drm_gem_cma_vm_ops, - .dumb_create = kirin_gem_cma_dumb_create, - - .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 = "kirin", - .desc = "Hisilicon Kirin SoCs' DRM Driver", - .date = "20150718", - .major = 1, - .minor = 0, -}; +static int kirin_drm_kms_cleanup(struct drm_device *dev) +{ + drm_kms_helper_poll_fini(dev); + kirin_drm_private_cleanup(dev); + drm_mode_config_cleanup(dev); -static int compare_of(struct device *dev, void *data) + return 0; +} + +static int kirin_drm_connectors_register(struct drm_device *dev) { - return dev->of_node == data; + struct drm_connector *connector; + struct drm_connector *failed_connector; + struct drm_connector_list_iter conn_iter; + int ret; + + mutex_lock(&dev->mode_config.mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + ret = drm_connector_register(connector); + if (ret) { + failed_connector = connector; + goto err; + } + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + + return 0; + +err: + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (failed_connector == connector) + break; + drm_connector_unregister(connector); + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + + return ret; } static int kirin_drm_bind(struct device *dev) { - struct drm_driver *driver = &kirin_drm_driver; + struct kirin_drm_data *driver_data; struct drm_device *drm_dev; int ret; - drm_dev = drm_dev_alloc(driver, dev); + driver_data = (struct kirin_drm_data *)of_device_get_match_data(dev); + if (!driver_data) + return -EINVAL; + + drm_dev = drm_dev_alloc(driver_data->driver, dev); if (IS_ERR(drm_dev)) return PTR_ERR(drm_dev); + dev_set_drvdata(dev, drm_dev); - ret = kirin_drm_kms_init(drm_dev); + /* display controller init */ + ret = kirin_drm_kms_init(drm_dev, driver_data); if (ret) goto err_drm_dev_put; @@ -163,8 +279,17 @@ static int kirin_drm_bind(struct device *dev) drm_fbdev_generic_setup(drm_dev, 32); + /* connectors should be registered after drm device register */ + if (driver_data->register_connects) { + ret = kirin_drm_connectors_register(drm_dev); + if (ret) + goto err_drm_dev_unregister; + } + return 0; +err_drm_dev_unregister: + drm_dev_unregister(drm_dev); err_kms_cleanup: kirin_drm_kms_cleanup(drm_dev); err_drm_dev_put: @@ -194,12 +319,6 @@ static int kirin_drm_platform_probe(struct platform_device *pdev) struct component_match *match = NULL; struct device_node *remote; - dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev); - if (!dc_ops) { - DRM_ERROR("failed to get dt id data\n"); - return -EINVAL; - } - remote = of_graph_get_remote_node(np, 0, 0); if (!remote) return -ENODEV; @@ -208,20 +327,17 @@ static int kirin_drm_platform_probe(struct platform_device *pdev) of_node_put(remote); return component_master_add_with_match(dev, &kirin_drm_ops, match); - - return 0; } static int kirin_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &kirin_drm_ops); - dc_ops = NULL; return 0; } static const struct of_device_id kirin_drm_dt_ids[] = { { .compatible = "hisilicon,hi6220-ade", - .data = &ade_dc_ops, + .data = &ade_driver_data, }, { /* end node */ }, }; diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h index 22d1291668cd..4d5c05a24065 100644 --- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h +++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h @@ -7,14 +7,52 @@ #ifndef __KIRIN_DRM_DRV_H__ #define __KIRIN_DRM_DRV_H__ -#define MAX_CRTC 2 +#define to_kirin_crtc(crtc) \ + container_of(crtc, struct kirin_crtc, base) + +#define to_kirin_plane(plane) \ + container_of(plane, struct kirin_plane, base) + +/* kirin-format translate table */ +struct kirin_format { + u32 pixel_format; + u32 hw_format; +}; + +struct kirin_crtc { + struct drm_crtc base; + void *hw_ctx; + bool enable; +}; + +struct kirin_plane { + struct drm_plane base; + void *hw_ctx; + u32 ch; +}; /* display controller init/cleanup ops */ -struct kirin_dc_ops { - int (*init)(struct platform_device *pdev); - void (*cleanup)(struct platform_device *pdev); +struct kirin_drm_data { + const u32 *channel_formats; + u32 channel_formats_cnt; + int config_max_width; + int config_max_height; + bool register_connects; + u32 num_planes; + u32 prim_plane; + + struct drm_driver *driver; + const struct drm_crtc_helper_funcs *crtc_helper_funcs; + const struct drm_crtc_funcs *crtc_funcs; + const struct drm_plane_helper_funcs *plane_helper_funcs; + const struct drm_plane_funcs *plane_funcs; + const struct drm_mode_config_funcs *mode_config_funcs; + + void *(*alloc_hw_ctx)(struct platform_device *pdev, + struct drm_crtc *crtc); + void (*cleanup_hw_ctx)(void *hw_ctx); }; -extern const struct kirin_dc_ops ade_dc_ops; +extern struct kirin_drm_data ade_driver_data; #endif /* __KIRIN_DRM_DRV_H__ */ |