Message ID | 1505203739-29747-2-git-send-email-m.szyprowski@samsung.com |
---|---|
State | Superseded |
Headers | show |
Series | Exynos DRM: rewrite IPP subsystem and userspace API | expand |
Hi Marek, Tested-by: Hoegeun Kwon <hoegeun.kwon@samsung.com> Best regards, Hoegeun On 09/12/2017 05:08 PM, Marek Szyprowski wrote: > Exynos IPP will be rewritten, so remove current IPP core code and mark > existing drivers as BROKEN. > > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > --- > drivers/gpu/drm/exynos/Kconfig | 11 +- > drivers/gpu/drm/exynos/Makefile | 1 - > drivers/gpu/drm/exynos/exynos_drm_drv.c | 12 - > drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 - > drivers/gpu/drm/exynos/exynos_drm_ipp.c | 1806 ------------------------------- > drivers/gpu/drm/exynos/exynos_drm_ipp.h | 252 ----- > include/uapi/drm/exynos_drm.h | 192 +--- > 7 files changed, 4 insertions(+), 2272 deletions(-) > delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_ipp.c > delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_ipp.h > > diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig > index 305dc3d4ff77..88cff0e039b6 100644 > --- a/drivers/gpu/drm/exynos/Kconfig > +++ b/drivers/gpu/drm/exynos/Kconfig > @@ -94,26 +94,21 @@ config DRM_EXYNOS_G2D > help > Choose this option if you want to use Exynos G2D for DRM. > > -config DRM_EXYNOS_IPP > - bool "Image Post Processor" > - help > - Choose this option if you want to use IPP feature for DRM. > - > config DRM_EXYNOS_FIMC > bool "FIMC" > - depends on DRM_EXYNOS_IPP && MFD_SYSCON > + depends on BROKEN && MFD_SYSCON > help > Choose this option if you want to use Exynos FIMC for DRM. > > config DRM_EXYNOS_ROTATOR > bool "Rotator" > - depends on DRM_EXYNOS_IPP > + depends on BROKEN > help > Choose this option if you want to use Exynos Rotator for DRM. > > config DRM_EXYNOS_GSC > bool "GScaler" > - depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n > + depends on BROKEN && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n > help > Choose this option if you want to use Exynos GSC for DRM. > > diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile > index f663490e949d..09bb002c9555 100644 > --- a/drivers/gpu/drm/exynos/Makefile > +++ b/drivers/gpu/drm/exynos/Makefile > @@ -17,7 +17,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o > exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o > exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o > exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o > -exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o > exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o > exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o > exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o > diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c > index b1f7299600f0..7f19054ebce3 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c > @@ -28,7 +28,6 @@ > #include "exynos_drm_plane.h" > #include "exynos_drm_vidi.h" > #include "exynos_drm_g2d.h" > -#include "exynos_drm_ipp.h" > #include "exynos_drm_iommu.h" > > #define DRIVER_NAME "exynos" > @@ -115,14 +114,6 @@ static void exynos_drm_lastclose(struct drm_device *dev) > DRM_AUTH | DRM_RENDER_ALLOW), > DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, > DRM_AUTH | DRM_RENDER_ALLOW), > - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property, > - DRM_AUTH | DRM_RENDER_ALLOW), > - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property, > - DRM_AUTH | DRM_RENDER_ALLOW), > - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf, > - DRM_AUTH | DRM_RENDER_ALLOW), > - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl, > - DRM_AUTH | DRM_RENDER_ALLOW), > }; > > static const struct file_operations exynos_drm_driver_fops = { > @@ -272,9 +263,6 @@ struct exynos_drm_driver_info { > }, { > DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC), > }, { > - DRV_PTR(ipp_driver, CONFIG_DRM_EXYNOS_IPP), > - DRM_VIRTUAL_DEVICE > - }, { > &exynos_drm_platform_driver, > DRM_VIRTUAL_DEVICE > } > diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h > index cf131c2aa23e..21f4271c012a 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h > +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h > @@ -185,7 +185,6 @@ struct exynos_drm_g2d_private { > > struct drm_exynos_file_private { > struct exynos_drm_g2d_private *g2d_priv; > - struct device *ipp_dev; > }; > > /* > @@ -292,6 +291,5 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, > extern struct platform_driver fimc_driver; > extern struct platform_driver rotator_driver; > extern struct platform_driver gsc_driver; > -extern struct platform_driver ipp_driver; > extern struct platform_driver mic_driver; > #endif > diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c > deleted file mode 100644 > index 3edda18cc2d2..000000000000 > --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c > +++ /dev/null > @@ -1,1806 +0,0 @@ > -/* > - * Copyright (C) 2012 Samsung Electronics Co.Ltd > - * Authors: > - * Eunchul Kim <chulspro.kim@samsung.com> > - * Jinyoung Jeon <jy0.jeon@samsung.com> > - * Sangmin Lee <lsmin.lee@samsung.com> > - * > - * This program is free software; you can redistribute it and/or modify it > - * under the terms of the GNU General Public License as published by the > - * Free Software Foundation; either version 2 of the License, or (at your > - * option) any later version. > - * > - */ > -#include <linux/kernel.h> > -#include <linux/platform_device.h> > -#include <linux/types.h> > -#include <linux/clk.h> > -#include <linux/pm_runtime.h> > - > -#include <drm/drmP.h> > -#include <drm/exynos_drm.h> > -#include "exynos_drm_drv.h" > -#include "exynos_drm_gem.h" > -#include "exynos_drm_ipp.h" > -#include "exynos_drm_iommu.h" > - > -/* > - * IPP stands for Image Post Processing and > - * supports image scaler/rotator and input/output DMA operations. > - * using FIMC, GSC, Rotator, so on. > - * IPP is integration device driver of same attribute h/w > - */ > - > -/* > - * TODO > - * 1. expand command control id. > - * 2. integrate property and config. > - * 3. removed send_event id check routine. > - * 4. compare send_event id if needed. > - * 5. free subdrv_remove notifier callback list if needed. > - * 6. need to check subdrv_open about multi-open. > - * 7. need to power_on implement power and sysmmu ctrl. > - */ > - > -#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev)) > -#define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M) > - > -/* > - * A structure of event. > - * > - * @base: base of event. > - * @event: ipp event. > - */ > -struct drm_exynos_ipp_send_event { > - struct drm_pending_event base; > - struct drm_exynos_ipp_event event; > -}; > - > -/* > - * A structure of memory node. > - * > - * @list: list head to memory queue information. > - * @ops_id: id of operations. > - * @prop_id: id of property. > - * @buf_id: id of buffer. > - * @buf_info: gem objects and dma address, size. > - * @filp: a pointer to drm_file. > - */ > -struct drm_exynos_ipp_mem_node { > - struct list_head list; > - enum drm_exynos_ops_id ops_id; > - u32 prop_id; > - u32 buf_id; > - struct drm_exynos_ipp_buf_info buf_info; > -}; > - > -/* > - * A structure of ipp context. > - * > - * @subdrv: prepare initialization using subdrv. > - * @ipp_lock: lock for synchronization of access to ipp_idr. > - * @prop_lock: lock for synchronization of access to prop_idr. > - * @ipp_idr: ipp driver idr. > - * @prop_idr: property idr. > - * @event_workq: event work queue. > - * @cmd_workq: command work queue. > - */ > -struct ipp_context { > - struct exynos_drm_subdrv subdrv; > - struct mutex ipp_lock; > - struct mutex prop_lock; > - struct idr ipp_idr; > - struct idr prop_idr; > - struct workqueue_struct *event_workq; > - struct workqueue_struct *cmd_workq; > -}; > - > -static LIST_HEAD(exynos_drm_ippdrv_list); > -static DEFINE_MUTEX(exynos_drm_ippdrv_lock); > -static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); > - > -int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) > -{ > - mutex_lock(&exynos_drm_ippdrv_lock); > - list_add_tail(&ippdrv->drv_list, &exynos_drm_ippdrv_list); > - mutex_unlock(&exynos_drm_ippdrv_lock); > - > - return 0; > -} > - > -int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) > -{ > - mutex_lock(&exynos_drm_ippdrv_lock); > - list_del(&ippdrv->drv_list); > - mutex_unlock(&exynos_drm_ippdrv_lock); > - > - return 0; > -} > - > -static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj) > -{ > - int ret; > - > - mutex_lock(lock); > - ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL); > - mutex_unlock(lock); > - > - return ret; > -} > - > -static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) > -{ > - mutex_lock(lock); > - idr_remove(id_idr, id); > - mutex_unlock(lock); > -} > - > -static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id) > -{ > - void *obj; > - > - mutex_lock(lock); > - obj = idr_find(id_idr, id); > - mutex_unlock(lock); > - > - return obj; > -} > - > -static int ipp_check_driver(struct exynos_drm_ippdrv *ippdrv, > - struct drm_exynos_ipp_property *property) > -{ > - if (ippdrv->dedicated || (!ipp_is_m2m_cmd(property->cmd) && > - !pm_runtime_suspended(ippdrv->dev))) > - return -EBUSY; > - > - if (ippdrv->check_property && > - ippdrv->check_property(ippdrv->dev, property)) > - return -EINVAL; > - > - return 0; > -} > - > -static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, > - struct drm_exynos_ipp_property *property) > -{ > - struct exynos_drm_ippdrv *ippdrv; > - u32 ipp_id = property->ipp_id; > - int ret; > - > - if (ipp_id) { > - ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, ipp_id); > - if (!ippdrv) { > - DRM_DEBUG("ipp%d driver not found\n", ipp_id); > - return ERR_PTR(-ENODEV); > - } > - > - ret = ipp_check_driver(ippdrv, property); > - if (ret < 0) { > - DRM_DEBUG("ipp%d driver check error %d\n", ipp_id, ret); > - return ERR_PTR(ret); > - } > - > - return ippdrv; > - } else { > - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { > - ret = ipp_check_driver(ippdrv, property); > - if (ret == 0) > - return ippdrv; > - } > - > - DRM_DEBUG("cannot find driver suitable for given property.\n"); > - } > - > - return ERR_PTR(-ENODEV); > -} > - > -static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id) > -{ > - struct exynos_drm_ippdrv *ippdrv; > - struct drm_exynos_ipp_cmd_node *c_node; > - int count = 0; > - > - DRM_DEBUG_KMS("prop_id[%d]\n", prop_id); > - > - /* > - * This case is search ipp driver by prop_id handle. > - * sometimes, ipp subsystem find driver by prop_id. > - * e.g PAUSE state, queue buf, command control. > - */ > - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { > - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n", count++, ippdrv); > - > - mutex_lock(&ippdrv->cmd_lock); > - list_for_each_entry(c_node, &ippdrv->cmd_list, list) { > - if (c_node->property.prop_id == prop_id) { > - mutex_unlock(&ippdrv->cmd_lock); > - return ippdrv; > - } > - } > - mutex_unlock(&ippdrv->cmd_lock); > - } > - > - return ERR_PTR(-ENODEV); > -} > - > -int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, > - struct drm_file *file) > -{ > - struct drm_exynos_file_private *file_priv = file->driver_priv; > - struct device *dev = file_priv->ipp_dev; > - struct ipp_context *ctx = get_ipp_context(dev); > - struct drm_exynos_ipp_prop_list *prop_list = data; > - struct exynos_drm_ippdrv *ippdrv; > - int count = 0; > - > - if (!ctx) { > - DRM_ERROR("invalid context.\n"); > - return -EINVAL; > - } > - > - if (!prop_list) { > - DRM_ERROR("invalid property parameter.\n"); > - return -EINVAL; > - } > - > - DRM_DEBUG_KMS("ipp_id[%d]\n", prop_list->ipp_id); > - > - if (!prop_list->ipp_id) { > - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) > - count++; > - > - /* > - * Supports ippdrv list count for user application. > - * First step user application getting ippdrv count. > - * and second step getting ippdrv capability using ipp_id. > - */ > - prop_list->count = count; > - } else { > - /* > - * Getting ippdrv capability by ipp_id. > - * some device not supported wb, output interface. > - * so, user application detect correct ipp driver > - * using this ioctl. > - */ > - ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, > - prop_list->ipp_id); > - if (!ippdrv) { > - DRM_ERROR("not found ipp%d driver.\n", > - prop_list->ipp_id); > - return -ENODEV; > - } > - > - *prop_list = ippdrv->prop_list; > - } > - > - return 0; > -} > - > -static void ipp_print_property(struct drm_exynos_ipp_property *property, > - int idx) > -{ > - struct drm_exynos_ipp_config *config = &property->config[idx]; > - struct drm_exynos_pos *pos = &config->pos; > - struct drm_exynos_sz *sz = &config->sz; > - > - DRM_DEBUG_KMS("prop_id[%d]ops[%s]fmt[0x%x]\n", > - property->prop_id, idx ? "dst" : "src", config->fmt); > - > - DRM_DEBUG_KMS("pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n", > - pos->x, pos->y, pos->w, pos->h, > - sz->hsize, sz->vsize, config->flip, config->degree); > -} > - > -static struct drm_exynos_ipp_cmd_work *ipp_create_cmd_work(void) > -{ > - struct drm_exynos_ipp_cmd_work *cmd_work; > - > - cmd_work = kzalloc(sizeof(*cmd_work), GFP_KERNEL); > - if (!cmd_work) > - return ERR_PTR(-ENOMEM); > - > - INIT_WORK((struct work_struct *)cmd_work, ipp_sched_cmd); > - > - return cmd_work; > -} > - > -static struct drm_exynos_ipp_event_work *ipp_create_event_work(void) > -{ > - struct drm_exynos_ipp_event_work *event_work; > - > - event_work = kzalloc(sizeof(*event_work), GFP_KERNEL); > - if (!event_work) > - return ERR_PTR(-ENOMEM); > - > - INIT_WORK(&event_work->work, ipp_sched_event); > - > - return event_work; > -} > - > -int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, > - struct drm_file *file) > -{ > - struct drm_exynos_file_private *file_priv = file->driver_priv; > - struct device *dev = file_priv->ipp_dev; > - struct ipp_context *ctx = get_ipp_context(dev); > - struct drm_exynos_ipp_property *property = data; > - struct exynos_drm_ippdrv *ippdrv; > - struct drm_exynos_ipp_cmd_node *c_node; > - u32 prop_id; > - int ret, i; > - > - if (!ctx) { > - DRM_ERROR("invalid context.\n"); > - return -EINVAL; > - } > - > - if (!property) { > - DRM_ERROR("invalid property parameter.\n"); > - return -EINVAL; > - } > - > - prop_id = property->prop_id; > - > - /* > - * This is log print for user application property. > - * user application set various property. > - */ > - for_each_ipp_ops(i) > - ipp_print_property(property, i); > - > - /* > - * In case prop_id is not zero try to set existing property. > - */ > - if (prop_id) { > - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, prop_id); > - > - if (!c_node || c_node->filp != file) { > - DRM_DEBUG_KMS("prop_id[%d] not found\n", prop_id); > - return -EINVAL; > - } > - > - if (c_node->state != IPP_STATE_STOP) { > - DRM_DEBUG_KMS("prop_id[%d] not stopped\n", prop_id); > - return -EINVAL; > - } > - > - c_node->property = *property; > - > - return 0; > - } > - > - /* find ipp driver using ipp id */ > - ippdrv = ipp_find_driver(ctx, property); > - if (IS_ERR(ippdrv)) { > - DRM_ERROR("failed to get ipp driver.\n"); > - return -EINVAL; > - } > - > - /* allocate command node */ > - c_node = kzalloc(sizeof(*c_node), GFP_KERNEL); > - if (!c_node) > - return -ENOMEM; > - > - ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node); > - if (ret < 0) { > - DRM_ERROR("failed to create id.\n"); > - goto err_clear; > - } > - property->prop_id = ret; > - > - DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[%pK]\n", > - property->prop_id, property->cmd, ippdrv); > - > - /* stored property information and ippdrv in private data */ > - c_node->property = *property; > - c_node->state = IPP_STATE_IDLE; > - c_node->filp = file; > - > - c_node->start_work = ipp_create_cmd_work(); > - if (IS_ERR(c_node->start_work)) { > - DRM_ERROR("failed to create start work.\n"); > - ret = PTR_ERR(c_node->start_work); > - goto err_remove_id; > - } > - > - c_node->stop_work = ipp_create_cmd_work(); > - if (IS_ERR(c_node->stop_work)) { > - DRM_ERROR("failed to create stop work.\n"); > - ret = PTR_ERR(c_node->stop_work); > - goto err_free_start; > - } > - > - c_node->event_work = ipp_create_event_work(); > - if (IS_ERR(c_node->event_work)) { > - DRM_ERROR("failed to create event work.\n"); > - ret = PTR_ERR(c_node->event_work); > - goto err_free_stop; > - } > - > - mutex_init(&c_node->lock); > - mutex_init(&c_node->mem_lock); > - mutex_init(&c_node->event_lock); > - > - init_completion(&c_node->start_complete); > - init_completion(&c_node->stop_complete); > - > - for_each_ipp_ops(i) > - INIT_LIST_HEAD(&c_node->mem_list[i]); > - > - INIT_LIST_HEAD(&c_node->event_list); > - mutex_lock(&ippdrv->cmd_lock); > - list_add_tail(&c_node->list, &ippdrv->cmd_list); > - mutex_unlock(&ippdrv->cmd_lock); > - > - /* make dedicated state without m2m */ > - if (!ipp_is_m2m_cmd(property->cmd)) > - ippdrv->dedicated = true; > - > - return 0; > - > -err_free_stop: > - kfree(c_node->stop_work); > -err_free_start: > - kfree(c_node->start_work); > -err_remove_id: > - ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, property->prop_id); > -err_clear: > - kfree(c_node); > - return ret; > -} > - > -static int ipp_validate_mem_node(struct drm_device *drm_dev, > - struct drm_exynos_ipp_mem_node *m_node, > - struct drm_exynos_ipp_cmd_node *c_node) > -{ > - struct drm_exynos_ipp_config *ipp_cfg; > - unsigned int num_plane; > - unsigned long size, buf_size = 0, plane_size, img_size = 0; > - unsigned int bpp, width, height; > - int i; > - > - ipp_cfg = &c_node->property.config[m_node->ops_id]; > - num_plane = drm_format_num_planes(ipp_cfg->fmt); > - > - /** > - * This is a rather simplified validation of a memory node. > - * It basically verifies provided gem object handles > - * and the buffer sizes with respect to current configuration. > - * This is not the best that can be done > - * but it seems more than enough > - */ > - for (i = 0; i < num_plane; ++i) { > - width = ipp_cfg->sz.hsize; > - height = ipp_cfg->sz.vsize; > - bpp = drm_format_plane_cpp(ipp_cfg->fmt, i); > - > - /* > - * The result of drm_format_plane_cpp() for chroma planes must > - * be used with drm_format_xxxx_chroma_subsampling() for > - * correct result. > - */ > - if (i > 0) { > - width /= drm_format_horz_chroma_subsampling( > - ipp_cfg->fmt); > - height /= drm_format_vert_chroma_subsampling( > - ipp_cfg->fmt); > - } > - plane_size = width * height * bpp; > - img_size += plane_size; > - > - if (m_node->buf_info.handles[i]) { > - size = exynos_drm_gem_get_size(drm_dev, > - m_node->buf_info.handles[i], > - c_node->filp); > - if (plane_size > size) { > - DRM_ERROR( > - "buffer %d is smaller than required\n", > - i); > - return -EINVAL; > - } > - > - buf_size += size; > - } > - } > - > - if (buf_size < img_size) { > - DRM_ERROR("size of buffers(%lu) is smaller than image(%lu)\n", > - buf_size, img_size); > - return -EINVAL; > - } > - > - return 0; > -} > - > -static int ipp_put_mem_node(struct drm_device *drm_dev, > - struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_mem_node *m_node) > -{ > - int i; > - > - DRM_DEBUG_KMS("node[%pK]\n", m_node); > - > - if (!m_node) { > - DRM_ERROR("invalid dequeue node.\n"); > - return -EFAULT; > - } > - > - DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); > - > - /* put gem buffer */ > - for_each_ipp_planar(i) { > - unsigned long handle = m_node->buf_info.handles[i]; > - if (handle) > - exynos_drm_gem_put_dma_addr(drm_dev, handle, > - c_node->filp); > - } > - > - list_del(&m_node->list); > - kfree(m_node); > - > - return 0; > -} > - > -static struct drm_exynos_ipp_mem_node > - *ipp_get_mem_node(struct drm_device *drm_dev, > - struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_queue_buf *qbuf) > -{ > - struct drm_exynos_ipp_mem_node *m_node; > - struct drm_exynos_ipp_buf_info *buf_info; > - int i; > - > - m_node = kzalloc(sizeof(*m_node), GFP_KERNEL); > - if (!m_node) > - return ERR_PTR(-ENOMEM); > - > - buf_info = &m_node->buf_info; > - > - /* operations, buffer id */ > - m_node->ops_id = qbuf->ops_id; > - m_node->prop_id = qbuf->prop_id; > - m_node->buf_id = qbuf->buf_id; > - INIT_LIST_HEAD(&m_node->list); > - > - DRM_DEBUG_KMS("m_node[%pK]ops_id[%d]\n", m_node, qbuf->ops_id); > - DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id); > - > - for_each_ipp_planar(i) { > - DRM_DEBUG_KMS("i[%d]handle[0x%x]\n", i, qbuf->handle[i]); > - > - /* get dma address by handle */ > - if (qbuf->handle[i]) { > - dma_addr_t *addr; > - > - addr = exynos_drm_gem_get_dma_addr(drm_dev, > - qbuf->handle[i], c_node->filp); > - if (IS_ERR(addr)) { > - DRM_ERROR("failed to get addr.\n"); > - ipp_put_mem_node(drm_dev, c_node, m_node); > - return ERR_PTR(-EFAULT); > - } > - > - buf_info->handles[i] = qbuf->handle[i]; > - buf_info->base[i] = *addr; > - DRM_DEBUG_KMS("i[%d]base[%pad]hd[0x%lx]\n", i, > - &buf_info->base[i], buf_info->handles[i]); > - } > - } > - > - mutex_lock(&c_node->mem_lock); > - if (ipp_validate_mem_node(drm_dev, m_node, c_node)) { > - ipp_put_mem_node(drm_dev, c_node, m_node); > - mutex_unlock(&c_node->mem_lock); > - return ERR_PTR(-EFAULT); > - } > - list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); > - mutex_unlock(&c_node->mem_lock); > - > - return m_node; > -} > - > -static void ipp_clean_mem_nodes(struct drm_device *drm_dev, > - struct drm_exynos_ipp_cmd_node *c_node, int ops) > -{ > - struct drm_exynos_ipp_mem_node *m_node, *tm_node; > - struct list_head *head = &c_node->mem_list[ops]; > - > - mutex_lock(&c_node->mem_lock); > - > - list_for_each_entry_safe(m_node, tm_node, head, list) { > - int ret; > - > - ret = ipp_put_mem_node(drm_dev, c_node, m_node); > - if (ret) > - DRM_ERROR("failed to put m_node.\n"); > - } > - > - mutex_unlock(&c_node->mem_lock); > -} > - > -static int ipp_get_event(struct drm_device *drm_dev, > - struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_queue_buf *qbuf) > -{ > - struct drm_exynos_ipp_send_event *e; > - int ret; > - > - DRM_DEBUG_KMS("ops_id[%d]buf_id[%d]\n", qbuf->ops_id, qbuf->buf_id); > - > - e = kzalloc(sizeof(*e), GFP_KERNEL); > - if (!e) > - return -ENOMEM; > - > - /* make event */ > - e->event.base.type = DRM_EXYNOS_IPP_EVENT; > - e->event.base.length = sizeof(e->event); > - e->event.user_data = qbuf->user_data; > - e->event.prop_id = qbuf->prop_id; > - e->event.buf_id[EXYNOS_DRM_OPS_DST] = qbuf->buf_id; > - > - ret = drm_event_reserve_init(drm_dev, c_node->filp, &e->base, &e->event.base); > - if (ret) { > - kfree(e); > - return ret; > - } > - > - mutex_lock(&c_node->event_lock); > - list_add_tail(&e->base.link, &c_node->event_list); > - mutex_unlock(&c_node->event_lock); > - > - return 0; > -} > - > -static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_queue_buf *qbuf) > -{ > - struct drm_exynos_ipp_send_event *e, *te; > - int count = 0; > - > - mutex_lock(&c_node->event_lock); > - list_for_each_entry_safe(e, te, &c_node->event_list, base.link) { > - DRM_DEBUG_KMS("count[%d]e[%pK]\n", count++, e); > - > - /* > - * qbuf == NULL condition means all event deletion. > - * stop operations want to delete all event list. > - * another case delete only same buf id. > - */ > - if (!qbuf) { > - /* delete list */ > - list_del(&e->base.link); > - kfree(e); > - } > - > - /* compare buffer id */ > - if (qbuf && (qbuf->buf_id == > - e->event.buf_id[EXYNOS_DRM_OPS_DST])) { > - /* delete list */ > - list_del(&e->base.link); > - kfree(e); > - goto out_unlock; > - } > - } > - > -out_unlock: > - mutex_unlock(&c_node->event_lock); > - return; > -} > - > -static void ipp_clean_cmd_node(struct ipp_context *ctx, > - struct drm_exynos_ipp_cmd_node *c_node) > -{ > - int i; > - > - /* cancel works */ > - cancel_work_sync(&c_node->start_work->work); > - cancel_work_sync(&c_node->stop_work->work); > - cancel_work_sync(&c_node->event_work->work); > - > - /* put event */ > - ipp_put_event(c_node, NULL); > - > - for_each_ipp_ops(i) > - ipp_clean_mem_nodes(ctx->subdrv.drm_dev, c_node, i); > - > - /* delete list */ > - list_del(&c_node->list); > - > - ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, > - c_node->property.prop_id); > - > - /* destroy mutex */ > - mutex_destroy(&c_node->lock); > - mutex_destroy(&c_node->mem_lock); > - mutex_destroy(&c_node->event_lock); > - > - /* free command node */ > - kfree(c_node->start_work); > - kfree(c_node->stop_work); > - kfree(c_node->event_work); > - kfree(c_node); > -} > - > -static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) > -{ > - switch (c_node->property.cmd) { > - case IPP_CMD_WB: > - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); > - case IPP_CMD_OUTPUT: > - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]); > - case IPP_CMD_M2M: > - default: > - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) && > - !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); > - } > -} > - > -static struct drm_exynos_ipp_mem_node > - *ipp_find_mem_node(struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_queue_buf *qbuf) > -{ > - struct drm_exynos_ipp_mem_node *m_node; > - struct list_head *head; > - int count = 0; > - > - DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id); > - > - /* source/destination memory list */ > - head = &c_node->mem_list[qbuf->ops_id]; > - > - /* find memory node from memory list */ > - list_for_each_entry(m_node, head, list) { > - DRM_DEBUG_KMS("count[%d]m_node[%pK]\n", count++, m_node); > - > - /* compare buffer id */ > - if (m_node->buf_id == qbuf->buf_id) > - return m_node; > - } > - > - return NULL; > -} > - > -static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv, > - struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_mem_node *m_node) > -{ > - struct exynos_drm_ipp_ops *ops = NULL; > - int ret = 0; > - > - DRM_DEBUG_KMS("node[%pK]\n", m_node); > - > - if (!m_node) { > - DRM_ERROR("invalid queue node.\n"); > - return -EFAULT; > - } > - > - DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); > - > - /* get operations callback */ > - ops = ippdrv->ops[m_node->ops_id]; > - if (!ops) { > - DRM_ERROR("not support ops.\n"); > - return -EFAULT; > - } > - > - /* set address and enable irq */ > - if (ops->set_addr) { > - ret = ops->set_addr(ippdrv->dev, &m_node->buf_info, > - m_node->buf_id, IPP_BUF_ENQUEUE); > - if (ret) { > - DRM_ERROR("failed to set addr.\n"); > - return ret; > - } > - } > - > - return ret; > -} > - > -static void ipp_handle_cmd_work(struct device *dev, > - struct exynos_drm_ippdrv *ippdrv, > - struct drm_exynos_ipp_cmd_work *cmd_work, > - struct drm_exynos_ipp_cmd_node *c_node) > -{ > - struct ipp_context *ctx = get_ipp_context(dev); > - > - cmd_work->ippdrv = ippdrv; > - cmd_work->c_node = c_node; > - queue_work(ctx->cmd_workq, &cmd_work->work); > -} > - > -static int ipp_queue_buf_with_run(struct device *dev, > - struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_mem_node *m_node, > - struct drm_exynos_ipp_queue_buf *qbuf) > -{ > - struct exynos_drm_ippdrv *ippdrv; > - struct drm_exynos_ipp_property *property; > - struct exynos_drm_ipp_ops *ops; > - int ret; > - > - ippdrv = ipp_find_drv_by_handle(qbuf->prop_id); > - if (IS_ERR(ippdrv)) { > - DRM_ERROR("failed to get ipp driver.\n"); > - return -EFAULT; > - } > - > - ops = ippdrv->ops[qbuf->ops_id]; > - if (!ops) { > - DRM_ERROR("failed to get ops.\n"); > - return -EFAULT; > - } > - > - property = &c_node->property; > - > - if (c_node->state != IPP_STATE_START) { > - DRM_DEBUG_KMS("bypass for invalid state.\n"); > - return 0; > - } > - > - mutex_lock(&c_node->mem_lock); > - if (!ipp_check_mem_list(c_node)) { > - mutex_unlock(&c_node->mem_lock); > - DRM_DEBUG_KMS("empty memory.\n"); > - return 0; > - } > - > - /* > - * If set destination buffer and enabled clock, > - * then m2m operations need start operations at queue_buf > - */ > - if (ipp_is_m2m_cmd(property->cmd)) { > - struct drm_exynos_ipp_cmd_work *cmd_work = c_node->start_work; > - > - cmd_work->ctrl = IPP_CTRL_PLAY; > - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); > - } else { > - ret = ipp_set_mem_node(ippdrv, c_node, m_node); > - if (ret) { > - mutex_unlock(&c_node->mem_lock); > - DRM_ERROR("failed to set m node.\n"); > - return ret; > - } > - } > - mutex_unlock(&c_node->mem_lock); > - > - return 0; > -} > - > -static void ipp_clean_queue_buf(struct drm_device *drm_dev, > - struct drm_exynos_ipp_cmd_node *c_node, > - struct drm_exynos_ipp_queue_buf *qbuf) > -{ > - struct drm_exynos_ipp_mem_node *m_node, *tm_node; > - > - /* delete list */ > - mutex_lock(&c_node->mem_lock); > - list_for_each_entry_safe(m_node, tm_node, > - &c_node->mem_list[qbuf->ops_id], list) { > - if (m_node->buf_id == qbuf->buf_id && > - m_node->ops_id == qbuf->ops_id) > - ipp_put_mem_node(drm_dev, c_node, m_node); > - } > - mutex_unlock(&c_node->mem_lock); > -} > - > -int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, > - struct drm_file *file) > -{ > - struct drm_exynos_file_private *file_priv = file->driver_priv; > - struct device *dev = file_priv->ipp_dev; > - struct ipp_context *ctx = get_ipp_context(dev); > - struct drm_exynos_ipp_queue_buf *qbuf = data; > - struct drm_exynos_ipp_cmd_node *c_node; > - struct drm_exynos_ipp_mem_node *m_node; > - int ret; > - > - if (!qbuf) { > - DRM_ERROR("invalid buf parameter.\n"); > - return -EINVAL; > - } > - > - if (qbuf->ops_id >= EXYNOS_DRM_OPS_MAX) { > - DRM_ERROR("invalid ops parameter.\n"); > - return -EINVAL; > - } > - > - DRM_DEBUG_KMS("prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n", > - qbuf->prop_id, qbuf->ops_id ? "dst" : "src", > - qbuf->buf_id, qbuf->buf_type); > - > - /* find command node */ > - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, > - qbuf->prop_id); > - if (!c_node || c_node->filp != file) { > - DRM_ERROR("failed to get command node.\n"); > - return -ENODEV; > - } > - > - /* buffer control */ > - switch (qbuf->buf_type) { > - case IPP_BUF_ENQUEUE: > - /* get memory node */ > - m_node = ipp_get_mem_node(drm_dev, c_node, qbuf); > - if (IS_ERR(m_node)) { > - DRM_ERROR("failed to get m_node.\n"); > - return PTR_ERR(m_node); > - } > - > - /* > - * first step get event for destination buffer. > - * and second step when M2M case run with destination buffer > - * if needed. > - */ > - if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) { > - /* get event for destination buffer */ > - ret = ipp_get_event(drm_dev, c_node, qbuf); > - if (ret) { > - DRM_ERROR("failed to get event.\n"); > - goto err_clean_node; > - } > - > - /* > - * M2M case run play control for streaming feature. > - * other case set address and waiting. > - */ > - ret = ipp_queue_buf_with_run(dev, c_node, m_node, qbuf); > - if (ret) { > - DRM_ERROR("failed to run command.\n"); > - goto err_clean_node; > - } > - } > - break; > - case IPP_BUF_DEQUEUE: > - mutex_lock(&c_node->lock); > - > - /* put event for destination buffer */ > - if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) > - ipp_put_event(c_node, qbuf); > - > - ipp_clean_queue_buf(drm_dev, c_node, qbuf); > - > - mutex_unlock(&c_node->lock); > - break; > - default: > - DRM_ERROR("invalid buffer control.\n"); > - return -EINVAL; > - } > - > - return 0; > - > -err_clean_node: > - DRM_ERROR("clean memory nodes.\n"); > - > - ipp_clean_queue_buf(drm_dev, c_node, qbuf); > - return ret; > -} > - > -static bool exynos_drm_ipp_check_valid(struct device *dev, > - enum drm_exynos_ipp_ctrl ctrl, enum drm_exynos_ipp_state state) > -{ > - if (ctrl != IPP_CTRL_PLAY) { > - if (pm_runtime_suspended(dev)) { > - DRM_ERROR("pm:runtime_suspended.\n"); > - goto err_status; > - } > - } > - > - switch (ctrl) { > - case IPP_CTRL_PLAY: > - if (state != IPP_STATE_IDLE) > - goto err_status; > - break; > - case IPP_CTRL_STOP: > - if (state == IPP_STATE_STOP) > - goto err_status; > - break; > - case IPP_CTRL_PAUSE: > - if (state != IPP_STATE_START) > - goto err_status; > - break; > - case IPP_CTRL_RESUME: > - if (state != IPP_STATE_STOP) > - goto err_status; > - break; > - default: > - DRM_ERROR("invalid state.\n"); > - goto err_status; > - } > - > - return true; > - > -err_status: > - DRM_ERROR("invalid status:ctrl[%d]state[%d]\n", ctrl, state); > - return false; > -} > - > -int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, > - struct drm_file *file) > -{ > - struct drm_exynos_file_private *file_priv = file->driver_priv; > - struct exynos_drm_ippdrv *ippdrv = NULL; > - struct device *dev = file_priv->ipp_dev; > - struct ipp_context *ctx = get_ipp_context(dev); > - struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl = data; > - struct drm_exynos_ipp_cmd_work *cmd_work; > - struct drm_exynos_ipp_cmd_node *c_node; > - > - if (!ctx) { > - DRM_ERROR("invalid context.\n"); > - return -EINVAL; > - } > - > - if (!cmd_ctrl) { > - DRM_ERROR("invalid control parameter.\n"); > - return -EINVAL; > - } > - > - DRM_DEBUG_KMS("ctrl[%d]prop_id[%d]\n", > - cmd_ctrl->ctrl, cmd_ctrl->prop_id); > - > - ippdrv = ipp_find_drv_by_handle(cmd_ctrl->prop_id); > - if (IS_ERR(ippdrv)) { > - DRM_ERROR("failed to get ipp driver.\n"); > - return PTR_ERR(ippdrv); > - } > - > - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, > - cmd_ctrl->prop_id); > - if (!c_node || c_node->filp != file) { > - DRM_ERROR("invalid command node list.\n"); > - return -ENODEV; > - } > - > - if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl, > - c_node->state)) { > - DRM_ERROR("invalid state.\n"); > - return -EINVAL; > - } > - > - switch (cmd_ctrl->ctrl) { > - case IPP_CTRL_PLAY: > - if (pm_runtime_suspended(ippdrv->dev)) > - pm_runtime_get_sync(ippdrv->dev); > - > - c_node->state = IPP_STATE_START; > - > - cmd_work = c_node->start_work; > - cmd_work->ctrl = cmd_ctrl->ctrl; > - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); > - break; > - case IPP_CTRL_STOP: > - cmd_work = c_node->stop_work; > - cmd_work->ctrl = cmd_ctrl->ctrl; > - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); > - > - if (!wait_for_completion_timeout(&c_node->stop_complete, > - msecs_to_jiffies(300))) { > - DRM_ERROR("timeout stop:prop_id[%d]\n", > - c_node->property.prop_id); > - } > - > - c_node->state = IPP_STATE_STOP; > - ippdrv->dedicated = false; > - mutex_lock(&ippdrv->cmd_lock); > - ipp_clean_cmd_node(ctx, c_node); > - > - if (list_empty(&ippdrv->cmd_list)) > - pm_runtime_put_sync(ippdrv->dev); > - mutex_unlock(&ippdrv->cmd_lock); > - break; > - case IPP_CTRL_PAUSE: > - cmd_work = c_node->stop_work; > - cmd_work->ctrl = cmd_ctrl->ctrl; > - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); > - > - if (!wait_for_completion_timeout(&c_node->stop_complete, > - msecs_to_jiffies(200))) { > - DRM_ERROR("timeout stop:prop_id[%d]\n", > - c_node->property.prop_id); > - } > - > - c_node->state = IPP_STATE_STOP; > - break; > - case IPP_CTRL_RESUME: > - c_node->state = IPP_STATE_START; > - cmd_work = c_node->start_work; > - cmd_work->ctrl = cmd_ctrl->ctrl; > - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); > - break; > - default: > - DRM_ERROR("could not support this state currently.\n"); > - return -EINVAL; > - } > - > - DRM_DEBUG_KMS("done ctrl[%d]prop_id[%d]\n", > - cmd_ctrl->ctrl, cmd_ctrl->prop_id); > - > - return 0; > -} > - > -int exynos_drm_ippnb_register(struct notifier_block *nb) > -{ > - return blocking_notifier_chain_register( > - &exynos_drm_ippnb_list, nb); > -} > - > -int exynos_drm_ippnb_unregister(struct notifier_block *nb) > -{ > - return blocking_notifier_chain_unregister( > - &exynos_drm_ippnb_list, nb); > -} > - > -int exynos_drm_ippnb_send_event(unsigned long val, void *v) > -{ > - return blocking_notifier_call_chain( > - &exynos_drm_ippnb_list, val, v); > -} > - > -static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv, > - struct drm_exynos_ipp_property *property) > -{ > - struct exynos_drm_ipp_ops *ops = NULL; > - bool swap = false; > - int ret, i; > - > - if (!property) { > - DRM_ERROR("invalid property parameter.\n"); > - return -EINVAL; > - } > - > - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); > - > - /* reset h/w block */ > - if (ippdrv->reset && > - ippdrv->reset(ippdrv->dev)) { > - return -EINVAL; > - } > - > - /* set source,destination operations */ > - for_each_ipp_ops(i) { > - struct drm_exynos_ipp_config *config = > - &property->config[i]; > - > - ops = ippdrv->ops[i]; > - if (!ops || !config) { > - DRM_ERROR("not support ops and config.\n"); > - return -EINVAL; > - } > - > - /* set format */ > - if (ops->set_fmt) { > - ret = ops->set_fmt(ippdrv->dev, config->fmt); > - if (ret) > - return ret; > - } > - > - /* set transform for rotation, flip */ > - if (ops->set_transf) { > - ret = ops->set_transf(ippdrv->dev, config->degree, > - config->flip, &swap); > - if (ret) > - return ret; > - } > - > - /* set size */ > - if (ops->set_size) { > - ret = ops->set_size(ippdrv->dev, swap, &config->pos, > - &config->sz); > - if (ret) > - return ret; > - } > - } > - > - return 0; > -} > - > -static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, > - struct drm_exynos_ipp_cmd_node *c_node) > -{ > - struct drm_exynos_ipp_mem_node *m_node; > - struct drm_exynos_ipp_property *property = &c_node->property; > - struct list_head *head; > - int ret, i; > - > - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); > - > - /* store command info in ippdrv */ > - ippdrv->c_node = c_node; > - > - mutex_lock(&c_node->mem_lock); > - if (!ipp_check_mem_list(c_node)) { > - DRM_DEBUG_KMS("empty memory.\n"); > - ret = -ENOMEM; > - goto err_unlock; > - } > - > - /* set current property in ippdrv */ > - ret = ipp_set_property(ippdrv, property); > - if (ret) { > - DRM_ERROR("failed to set property.\n"); > - ippdrv->c_node = NULL; > - goto err_unlock; > - } > - > - /* check command */ > - switch (property->cmd) { > - case IPP_CMD_M2M: > - for_each_ipp_ops(i) { > - /* source/destination memory list */ > - head = &c_node->mem_list[i]; > - > - m_node = list_first_entry(head, > - struct drm_exynos_ipp_mem_node, list); > - > - DRM_DEBUG_KMS("m_node[%pK]\n", m_node); > - > - ret = ipp_set_mem_node(ippdrv, c_node, m_node); > - if (ret) { > - DRM_ERROR("failed to set m node.\n"); > - goto err_unlock; > - } > - } > - break; > - case IPP_CMD_WB: > - /* destination memory list */ > - head = &c_node->mem_list[EXYNOS_DRM_OPS_DST]; > - > - list_for_each_entry(m_node, head, list) { > - ret = ipp_set_mem_node(ippdrv, c_node, m_node); > - if (ret) { > - DRM_ERROR("failed to set m node.\n"); > - goto err_unlock; > - } > - } > - break; > - case IPP_CMD_OUTPUT: > - /* source memory list */ > - head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; > - > - list_for_each_entry(m_node, head, list) { > - ret = ipp_set_mem_node(ippdrv, c_node, m_node); > - if (ret) { > - DRM_ERROR("failed to set m node.\n"); > - goto err_unlock; > - } > - } > - break; > - default: > - DRM_ERROR("invalid operations.\n"); > - ret = -EINVAL; > - goto err_unlock; > - } > - mutex_unlock(&c_node->mem_lock); > - > - DRM_DEBUG_KMS("cmd[%d]\n", property->cmd); > - > - /* start operations */ > - if (ippdrv->start) { > - ret = ippdrv->start(ippdrv->dev, property->cmd); > - if (ret) { > - DRM_ERROR("failed to start ops.\n"); > - ippdrv->c_node = NULL; > - return ret; > - } > - } > - > - return 0; > - > -err_unlock: > - mutex_unlock(&c_node->mem_lock); > - ippdrv->c_node = NULL; > - return ret; > -} > - > -static int ipp_stop_property(struct drm_device *drm_dev, > - struct exynos_drm_ippdrv *ippdrv, > - struct drm_exynos_ipp_cmd_node *c_node) > -{ > - struct drm_exynos_ipp_property *property = &c_node->property; > - int i; > - > - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); > - > - /* stop operations */ > - if (ippdrv->stop) > - ippdrv->stop(ippdrv->dev, property->cmd); > - > - /* check command */ > - switch (property->cmd) { > - case IPP_CMD_M2M: > - for_each_ipp_ops(i) > - ipp_clean_mem_nodes(drm_dev, c_node, i); > - break; > - case IPP_CMD_WB: > - ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_DST); > - break; > - case IPP_CMD_OUTPUT: > - ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_SRC); > - break; > - default: > - DRM_ERROR("invalid operations.\n"); > - return -EINVAL; > - } > - > - return 0; > -} > - > -void ipp_sched_cmd(struct work_struct *work) > -{ > - struct drm_exynos_ipp_cmd_work *cmd_work = > - container_of(work, struct drm_exynos_ipp_cmd_work, work); > - struct exynos_drm_ippdrv *ippdrv; > - struct drm_exynos_ipp_cmd_node *c_node; > - struct drm_exynos_ipp_property *property; > - int ret; > - > - ippdrv = cmd_work->ippdrv; > - if (!ippdrv) { > - DRM_ERROR("invalid ippdrv list.\n"); > - return; > - } > - > - c_node = cmd_work->c_node; > - if (!c_node) { > - DRM_ERROR("invalid command node list.\n"); > - return; > - } > - > - mutex_lock(&c_node->lock); > - > - property = &c_node->property; > - > - switch (cmd_work->ctrl) { > - case IPP_CTRL_PLAY: > - case IPP_CTRL_RESUME: > - ret = ipp_start_property(ippdrv, c_node); > - if (ret) { > - DRM_ERROR("failed to start property:prop_id[%d]\n", > - c_node->property.prop_id); > - goto err_unlock; > - } > - > - /* > - * M2M case supports wait_completion of transfer. > - * because M2M case supports single unit operation > - * with multiple queue. > - * M2M need to wait completion of data transfer. > - */ > - if (ipp_is_m2m_cmd(property->cmd)) { > - if (!wait_for_completion_timeout > - (&c_node->start_complete, msecs_to_jiffies(200))) { > - DRM_ERROR("timeout event:prop_id[%d]\n", > - c_node->property.prop_id); > - goto err_unlock; > - } > - } > - break; > - case IPP_CTRL_STOP: > - case IPP_CTRL_PAUSE: > - ret = ipp_stop_property(ippdrv->drm_dev, ippdrv, > - c_node); > - if (ret) { > - DRM_ERROR("failed to stop property.\n"); > - goto err_unlock; > - } > - > - complete(&c_node->stop_complete); > - break; > - default: > - DRM_ERROR("unknown control type\n"); > - break; > - } > - > - DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl); > - > -err_unlock: > - mutex_unlock(&c_node->lock); > -} > - > -static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, > - struct drm_exynos_ipp_cmd_node *c_node, int *buf_id) > -{ > - struct drm_device *drm_dev = ippdrv->drm_dev; > - struct drm_exynos_ipp_property *property = &c_node->property; > - struct drm_exynos_ipp_mem_node *m_node; > - struct drm_exynos_ipp_queue_buf qbuf; > - struct drm_exynos_ipp_send_event *e; > - struct list_head *head; > - struct timeval now; > - u32 tbuf_id[EXYNOS_DRM_OPS_MAX] = {0, }; > - int ret, i; > - > - for_each_ipp_ops(i) > - DRM_DEBUG_KMS("%s buf_id[%d]\n", i ? "dst" : "src", buf_id[i]); > - > - if (!drm_dev) { > - DRM_ERROR("failed to get drm_dev.\n"); > - return -EINVAL; > - } > - > - if (!property) { > - DRM_ERROR("failed to get property.\n"); > - return -EINVAL; > - } > - > - mutex_lock(&c_node->event_lock); > - if (list_empty(&c_node->event_list)) { > - DRM_DEBUG_KMS("event list is empty.\n"); > - ret = 0; > - goto err_event_unlock; > - } > - > - mutex_lock(&c_node->mem_lock); > - if (!ipp_check_mem_list(c_node)) { > - DRM_DEBUG_KMS("empty memory.\n"); > - ret = 0; > - goto err_mem_unlock; > - } > - > - /* check command */ > - switch (property->cmd) { > - case IPP_CMD_M2M: > - for_each_ipp_ops(i) { > - /* source/destination memory list */ > - head = &c_node->mem_list[i]; > - > - m_node = list_first_entry(head, > - struct drm_exynos_ipp_mem_node, list); > - > - tbuf_id[i] = m_node->buf_id; > - DRM_DEBUG_KMS("%s buf_id[%d]\n", > - i ? "dst" : "src", tbuf_id[i]); > - > - ret = ipp_put_mem_node(drm_dev, c_node, m_node); > - if (ret) > - DRM_ERROR("failed to put m_node.\n"); > - } > - break; > - case IPP_CMD_WB: > - /* clear buf for finding */ > - memset(&qbuf, 0x0, sizeof(qbuf)); > - qbuf.ops_id = EXYNOS_DRM_OPS_DST; > - qbuf.buf_id = buf_id[EXYNOS_DRM_OPS_DST]; > - > - /* get memory node entry */ > - m_node = ipp_find_mem_node(c_node, &qbuf); > - if (!m_node) { > - DRM_ERROR("empty memory node.\n"); > - ret = -ENOMEM; > - goto err_mem_unlock; > - } > - > - tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id; > - > - ret = ipp_put_mem_node(drm_dev, c_node, m_node); > - if (ret) > - DRM_ERROR("failed to put m_node.\n"); > - break; > - case IPP_CMD_OUTPUT: > - /* source memory list */ > - head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; > - > - m_node = list_first_entry(head, > - struct drm_exynos_ipp_mem_node, list); > - > - tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; > - > - ret = ipp_put_mem_node(drm_dev, c_node, m_node); > - if (ret) > - DRM_ERROR("failed to put m_node.\n"); > - break; > - default: > - DRM_ERROR("invalid operations.\n"); > - ret = -EINVAL; > - goto err_mem_unlock; > - } > - mutex_unlock(&c_node->mem_lock); > - > - if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST]) > - DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n", > - tbuf_id[1], buf_id[1], property->prop_id); > - > - /* > - * command node have event list of destination buffer > - * If destination buffer enqueue to mem list, > - * then we make event and link to event list tail. > - * so, we get first event for first enqueued buffer. > - */ > - e = list_first_entry(&c_node->event_list, > - struct drm_exynos_ipp_send_event, base.link); > - > - do_gettimeofday(&now); > - DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec); > - e->event.tv_sec = now.tv_sec; > - e->event.tv_usec = now.tv_usec; > - e->event.prop_id = property->prop_id; > - > - /* set buffer id about source destination */ > - for_each_ipp_ops(i) > - e->event.buf_id[i] = tbuf_id[i]; > - > - drm_send_event(drm_dev, &e->base); > - mutex_unlock(&c_node->event_lock); > - > - DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n", > - property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]); > - > - return 0; > - > -err_mem_unlock: > - mutex_unlock(&c_node->mem_lock); > -err_event_unlock: > - mutex_unlock(&c_node->event_lock); > - return ret; > -} > - > -void ipp_sched_event(struct work_struct *work) > -{ > - struct drm_exynos_ipp_event_work *event_work = > - container_of(work, struct drm_exynos_ipp_event_work, work); > - struct exynos_drm_ippdrv *ippdrv; > - struct drm_exynos_ipp_cmd_node *c_node; > - int ret; > - > - if (!event_work) { > - DRM_ERROR("failed to get event_work.\n"); > - return; > - } > - > - DRM_DEBUG_KMS("buf_id[%d]\n", event_work->buf_id[EXYNOS_DRM_OPS_DST]); > - > - ippdrv = event_work->ippdrv; > - if (!ippdrv) { > - DRM_ERROR("failed to get ipp driver.\n"); > - return; > - } > - > - c_node = ippdrv->c_node; > - if (!c_node) { > - DRM_ERROR("failed to get command node.\n"); > - return; > - } > - > - /* > - * IPP supports command thread, event thread synchronization. > - * If IPP close immediately from user land, then IPP make > - * synchronization with command thread, so make complete event. > - * or going out operations. > - */ > - if (c_node->state != IPP_STATE_START) { > - DRM_DEBUG_KMS("bypass state[%d]prop_id[%d]\n", > - c_node->state, c_node->property.prop_id); > - goto err_completion; > - } > - > - ret = ipp_send_event(ippdrv, c_node, event_work->buf_id); > - if (ret) { > - DRM_ERROR("failed to send event.\n"); > - goto err_completion; > - } > - > -err_completion: > - if (ipp_is_m2m_cmd(c_node->property.cmd)) > - complete(&c_node->start_complete); > -} > - > -static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) > -{ > - struct ipp_context *ctx = get_ipp_context(dev); > - struct exynos_drm_ippdrv *ippdrv; > - int ret, count = 0; > - > - /* get ipp driver entry */ > - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { > - ippdrv->drm_dev = drm_dev; > - > - ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv); > - if (ret < 0) { > - DRM_ERROR("failed to create id.\n"); > - goto err; > - } > - ippdrv->prop_list.ipp_id = ret; > - > - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]ipp_id[%d]\n", > - count++, ippdrv, ret); > - > - /* store parent device for node */ > - ippdrv->parent_dev = dev; > - > - /* store event work queue and handler */ > - ippdrv->event_workq = ctx->event_workq; > - ippdrv->sched_event = ipp_sched_event; > - INIT_LIST_HEAD(&ippdrv->cmd_list); > - mutex_init(&ippdrv->cmd_lock); > - > - ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); > - if (ret) { > - DRM_ERROR("failed to activate iommu\n"); > - goto err; > - } > - } > - > - return 0; > - > -err: > - /* get ipp driver entry */ > - list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, > - drv_list) { > - drm_iommu_detach_device(drm_dev, ippdrv->dev); > - > - ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, > - ippdrv->prop_list.ipp_id); > - } > - > - return ret; > -} > - > -static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) > -{ > - struct exynos_drm_ippdrv *ippdrv, *t; > - struct ipp_context *ctx = get_ipp_context(dev); > - > - /* get ipp driver entry */ > - list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) { > - drm_iommu_detach_device(drm_dev, ippdrv->dev); > - > - ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, > - ippdrv->prop_list.ipp_id); > - > - ippdrv->drm_dev = NULL; > - exynos_drm_ippdrv_unregister(ippdrv); > - } > -} > - > -static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev, > - struct drm_file *file) > -{ > - struct drm_exynos_file_private *file_priv = file->driver_priv; > - > - file_priv->ipp_dev = dev; > - > - DRM_DEBUG_KMS("done priv[%pK]\n", dev); > - > - return 0; > -} > - > -static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, > - struct drm_file *file) > -{ > - struct exynos_drm_ippdrv *ippdrv = NULL; > - struct ipp_context *ctx = get_ipp_context(dev); > - struct drm_exynos_ipp_cmd_node *c_node, *tc_node; > - int count = 0; > - > - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { > - mutex_lock(&ippdrv->cmd_lock); > - list_for_each_entry_safe(c_node, tc_node, > - &ippdrv->cmd_list, list) { > - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n", > - count++, ippdrv); > - > - if (c_node->filp == file) { > - /* > - * userland goto unnormal state. process killed. > - * and close the file. > - * so, IPP didn't called stop cmd ctrl. > - * so, we are make stop operation in this state. > - */ > - if (c_node->state == IPP_STATE_START) { > - ipp_stop_property(drm_dev, ippdrv, > - c_node); > - c_node->state = IPP_STATE_STOP; > - } > - > - ippdrv->dedicated = false; > - ipp_clean_cmd_node(ctx, c_node); > - if (list_empty(&ippdrv->cmd_list)) > - pm_runtime_put_sync(ippdrv->dev); > - } > - } > - mutex_unlock(&ippdrv->cmd_lock); > - } > - > - return; > -} > - > -static int ipp_probe(struct platform_device *pdev) > -{ > - struct device *dev = &pdev->dev; > - struct ipp_context *ctx; > - struct exynos_drm_subdrv *subdrv; > - int ret; > - > - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); > - if (!ctx) > - return -ENOMEM; > - > - mutex_init(&ctx->ipp_lock); > - mutex_init(&ctx->prop_lock); > - > - idr_init(&ctx->ipp_idr); > - idr_init(&ctx->prop_idr); > - > - /* > - * create single thread for ipp event > - * IPP supports event thread for IPP drivers. > - * IPP driver send event_work to this thread. > - * and IPP event thread send event to user process. > - */ > - ctx->event_workq = create_singlethread_workqueue("ipp_event"); > - if (!ctx->event_workq) { > - dev_err(dev, "failed to create event workqueue\n"); > - return -EINVAL; > - } > - > - /* > - * create single thread for ipp command > - * IPP supports command thread for user process. > - * user process make command node using set property ioctl. > - * and make start_work and send this work to command thread. > - * and then this command thread start property. > - */ > - ctx->cmd_workq = create_singlethread_workqueue("ipp_cmd"); > - if (!ctx->cmd_workq) { > - dev_err(dev, "failed to create cmd workqueue\n"); > - ret = -EINVAL; > - goto err_event_workq; > - } > - > - /* set sub driver informations */ > - subdrv = &ctx->subdrv; > - subdrv->dev = dev; > - subdrv->probe = ipp_subdrv_probe; > - subdrv->remove = ipp_subdrv_remove; > - subdrv->open = ipp_subdrv_open; > - subdrv->close = ipp_subdrv_close; > - > - platform_set_drvdata(pdev, ctx); > - > - ret = exynos_drm_subdrv_register(subdrv); > - if (ret < 0) { > - DRM_ERROR("failed to register drm ipp device.\n"); > - goto err_cmd_workq; > - } > - > - dev_info(dev, "drm ipp registered successfully.\n"); > - > - return 0; > - > -err_cmd_workq: > - destroy_workqueue(ctx->cmd_workq); > -err_event_workq: > - destroy_workqueue(ctx->event_workq); > - return ret; > -} > - > -static int ipp_remove(struct platform_device *pdev) > -{ > - struct ipp_context *ctx = platform_get_drvdata(pdev); > - > - /* unregister sub driver */ > - exynos_drm_subdrv_unregister(&ctx->subdrv); > - > - /* remove,destroy ipp idr */ > - idr_destroy(&ctx->ipp_idr); > - idr_destroy(&ctx->prop_idr); > - > - mutex_destroy(&ctx->ipp_lock); > - mutex_destroy(&ctx->prop_lock); > - > - /* destroy command, event work queue */ > - destroy_workqueue(ctx->cmd_workq); > - destroy_workqueue(ctx->event_workq); > - > - return 0; > -} > - > -struct platform_driver ipp_driver = { > - .probe = ipp_probe, > - .remove = ipp_remove, > - .driver = { > - .name = "exynos-drm-ipp", > - .owner = THIS_MODULE, > - }, > -}; > - > diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h > deleted file mode 100644 > index 2a61547a39d0..000000000000 > --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h > +++ /dev/null > @@ -1,252 +0,0 @@ > -/* > - * Copyright (c) 2012 Samsung Electronics Co., Ltd. > - * > - * Authors: > - * Eunchul Kim <chulspro.kim@samsung.com> > - * Jinyoung Jeon <jy0.jeon@samsung.com> > - * Sangmin Lee <lsmin.lee@samsung.com> > - * > - * This program is free software; you can redistribute it and/or modify it > - * under the terms of the GNU General Public License as published by the > - * Free Software Foundation; either version 2 of the License, or (at your > - * option) any later version. > - */ > - > -#ifndef _EXYNOS_DRM_IPP_H_ > -#define _EXYNOS_DRM_IPP_H_ > - > -#define for_each_ipp_ops(pos) \ > - for (pos = 0; pos < EXYNOS_DRM_OPS_MAX; pos++) > -#define for_each_ipp_planar(pos) \ > - for (pos = 0; pos < EXYNOS_DRM_PLANAR_MAX; pos++) > - > -#define IPP_GET_LCD_WIDTH _IOR('F', 302, int) > -#define IPP_GET_LCD_HEIGHT _IOR('F', 303, int) > -#define IPP_SET_WRITEBACK _IOW('F', 304, u32) > - > -/* definition of state */ > -enum drm_exynos_ipp_state { > - IPP_STATE_IDLE, > - IPP_STATE_START, > - IPP_STATE_STOP, > -}; > - > -/* > - * A structure of command work information. > - * @work: work structure. > - * @ippdrv: current work ippdrv. > - * @c_node: command node information. > - * @ctrl: command control. > - */ > -struct drm_exynos_ipp_cmd_work { > - struct work_struct work; > - struct exynos_drm_ippdrv *ippdrv; > - struct drm_exynos_ipp_cmd_node *c_node; > - enum drm_exynos_ipp_ctrl ctrl; > -}; > - > -/* > - * A structure of command node. > - * > - * @list: list head to command queue information. > - * @event_list: list head of event. > - * @mem_list: list head to source,destination memory queue information. > - * @lock: lock for synchronization of access to ioctl. > - * @mem_lock: lock for synchronization of access to memory nodes. > - * @event_lock: lock for synchronization of access to scheduled event. > - * @start_complete: completion of start of command. > - * @stop_complete: completion of stop of command. > - * @property: property information. > - * @start_work: start command work structure. > - * @stop_work: stop command work structure. > - * @event_work: event work structure. > - * @state: state of command node. > - * @filp: associated file pointer. > - */ > -struct drm_exynos_ipp_cmd_node { > - struct list_head list; > - struct list_head event_list; > - struct list_head mem_list[EXYNOS_DRM_OPS_MAX]; > - struct mutex lock; > - struct mutex mem_lock; > - struct mutex event_lock; > - struct completion start_complete; > - struct completion stop_complete; > - struct drm_exynos_ipp_property property; > - struct drm_exynos_ipp_cmd_work *start_work; > - struct drm_exynos_ipp_cmd_work *stop_work; > - struct drm_exynos_ipp_event_work *event_work; > - enum drm_exynos_ipp_state state; > - struct drm_file *filp; > -}; > - > -/* > - * A structure of buffer information. > - * > - * @handles: Y, Cb, Cr each gem object handle. > - * @base: Y, Cb, Cr each planar address. > - */ > -struct drm_exynos_ipp_buf_info { > - unsigned long handles[EXYNOS_DRM_PLANAR_MAX]; > - dma_addr_t base[EXYNOS_DRM_PLANAR_MAX]; > -}; > - > -/* > - * A structure of wb setting information. > - * > - * @enable: enable flag for wb. > - * @refresh: HZ of the refresh rate. > - */ > -struct drm_exynos_ipp_set_wb { > - __u32 enable; > - __u32 refresh; > -}; > - > -/* > - * A structure of event work information. > - * > - * @work: work structure. > - * @ippdrv: current work ippdrv. > - * @buf_id: id of src, dst buffer. > - */ > -struct drm_exynos_ipp_event_work { > - struct work_struct work; > - struct exynos_drm_ippdrv *ippdrv; > - u32 buf_id[EXYNOS_DRM_OPS_MAX]; > -}; > - > -/* > - * A structure of source,destination operations. > - * > - * @set_fmt: set format of image. > - * @set_transf: set transform(rotations, flip). > - * @set_size: set size of region. > - * @set_addr: set address for dma. > - */ > -struct exynos_drm_ipp_ops { > - int (*set_fmt)(struct device *dev, u32 fmt); > - int (*set_transf)(struct device *dev, > - enum drm_exynos_degree degree, > - enum drm_exynos_flip flip, bool *swap); > - int (*set_size)(struct device *dev, int swap, > - struct drm_exynos_pos *pos, struct drm_exynos_sz *sz); > - int (*set_addr)(struct device *dev, > - struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id, > - enum drm_exynos_ipp_buf_type buf_type); > -}; > - > -/* > - * A structure of ipp driver. > - * > - * @drv_list: list head for registed sub driver information. > - * @parent_dev: parent device information. > - * @dev: platform device. > - * @drm_dev: drm device. > - * @dedicated: dedicated ipp device. > - * @ops: source, destination operations. > - * @event_workq: event work queue. > - * @c_node: current command information. > - * @cmd_list: list head for command information. > - * @cmd_lock: lock for synchronization of access to cmd_list. > - * @prop_list: property informations of current ipp driver. > - * @check_property: check property about format, size, buffer. > - * @reset: reset ipp block. > - * @start: ipp each device start. > - * @stop: ipp each device stop. > - * @sched_event: work schedule handler. > - */ > -struct exynos_drm_ippdrv { > - struct list_head drv_list; > - struct device *parent_dev; > - struct device *dev; > - struct drm_device *drm_dev; > - bool dedicated; > - struct exynos_drm_ipp_ops *ops[EXYNOS_DRM_OPS_MAX]; > - struct workqueue_struct *event_workq; > - struct drm_exynos_ipp_cmd_node *c_node; > - struct list_head cmd_list; > - struct mutex cmd_lock; > - struct drm_exynos_ipp_prop_list prop_list; > - > - int (*check_property)(struct device *dev, > - struct drm_exynos_ipp_property *property); > - int (*reset)(struct device *dev); > - int (*start)(struct device *dev, enum drm_exynos_ipp_cmd cmd); > - void (*stop)(struct device *dev, enum drm_exynos_ipp_cmd cmd); > - void (*sched_event)(struct work_struct *work); > -}; > - > -#ifdef CONFIG_DRM_EXYNOS_IPP > -extern int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv); > -extern int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv); > -extern int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, > - struct drm_file *file); > -extern int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, > - struct drm_file *file); > -extern int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, > - struct drm_file *file); > -extern int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, > - struct drm_file *file); > -extern int exynos_drm_ippnb_register(struct notifier_block *nb); > -extern int exynos_drm_ippnb_unregister(struct notifier_block *nb); > -extern int exynos_drm_ippnb_send_event(unsigned long val, void *v); > -extern void ipp_sched_cmd(struct work_struct *work); > -extern void ipp_sched_event(struct work_struct *work); > - > -#else > -static inline int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) > -{ > - return -ENODEV; > -} > - > -static inline int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) > -{ > - return -ENODEV; > -} > - > -static inline int exynos_drm_ipp_get_property(struct drm_device *drm_dev, > - void *data, > - struct drm_file *file_priv) > -{ > - return -ENOTTY; > -} > - > -static inline int exynos_drm_ipp_set_property(struct drm_device *drm_dev, > - void *data, > - struct drm_file *file_priv) > -{ > - return -ENOTTY; > -} > - > -static inline int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, > - void *data, > - struct drm_file *file) > -{ > - return -ENOTTY; > -} > - > -static inline int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, > - void *data, > - struct drm_file *file) > -{ > - return -ENOTTY; > -} > - > -static inline int exynos_drm_ippnb_register(struct notifier_block *nb) > -{ > - return -ENODEV; > -} > - > -static inline int exynos_drm_ippnb_unregister(struct notifier_block *nb) > -{ > - return -ENODEV; > -} > - > -static inline int exynos_drm_ippnb_send_event(unsigned long val, void *v) > -{ > - return -ENOTTY; > -} > -#endif > - > -#endif /* _EXYNOS_DRM_IPP_H_ */ > - > diff --git a/include/uapi/drm/exynos_drm.h b/include/uapi/drm/exynos_drm.h > index cb3e9f9d029f..544db2cecb36 100644 > --- a/include/uapi/drm/exynos_drm.h > +++ b/include/uapi/drm/exynos_drm.h > @@ -134,172 +134,6 @@ struct drm_exynos_g2d_exec { > __u64 async; > }; > > -enum drm_exynos_ops_id { > - EXYNOS_DRM_OPS_SRC, > - EXYNOS_DRM_OPS_DST, > - EXYNOS_DRM_OPS_MAX, > -}; > - > -struct drm_exynos_sz { > - __u32 hsize; > - __u32 vsize; > -}; > - > -struct drm_exynos_pos { > - __u32 x; > - __u32 y; > - __u32 w; > - __u32 h; > -}; > - > -enum drm_exynos_flip { > - EXYNOS_DRM_FLIP_NONE = (0 << 0), > - EXYNOS_DRM_FLIP_VERTICAL = (1 << 0), > - EXYNOS_DRM_FLIP_HORIZONTAL = (1 << 1), > - EXYNOS_DRM_FLIP_BOTH = EXYNOS_DRM_FLIP_VERTICAL | > - EXYNOS_DRM_FLIP_HORIZONTAL, > -}; > - > -enum drm_exynos_degree { > - EXYNOS_DRM_DEGREE_0, > - EXYNOS_DRM_DEGREE_90, > - EXYNOS_DRM_DEGREE_180, > - EXYNOS_DRM_DEGREE_270, > -}; > - > -enum drm_exynos_planer { > - EXYNOS_DRM_PLANAR_Y, > - EXYNOS_DRM_PLANAR_CB, > - EXYNOS_DRM_PLANAR_CR, > - EXYNOS_DRM_PLANAR_MAX, > -}; > - > -/** > - * A structure for ipp supported property list. > - * > - * @version: version of this structure. > - * @ipp_id: id of ipp driver. > - * @count: count of ipp driver. > - * @writeback: flag of writeback supporting. > - * @flip: flag of flip supporting. > - * @degree: flag of degree information. > - * @csc: flag of csc supporting. > - * @crop: flag of crop supporting. > - * @scale: flag of scale supporting. > - * @refresh_min: min hz of refresh. > - * @refresh_max: max hz of refresh. > - * @crop_min: crop min resolution. > - * @crop_max: crop max resolution. > - * @scale_min: scale min resolution. > - * @scale_max: scale max resolution. > - */ > -struct drm_exynos_ipp_prop_list { > - __u32 version; > - __u32 ipp_id; > - __u32 count; > - __u32 writeback; > - __u32 flip; > - __u32 degree; > - __u32 csc; > - __u32 crop; > - __u32 scale; > - __u32 refresh_min; > - __u32 refresh_max; > - __u32 reserved; > - struct drm_exynos_sz crop_min; > - struct drm_exynos_sz crop_max; > - struct drm_exynos_sz scale_min; > - struct drm_exynos_sz scale_max; > -}; > - > -/** > - * A structure for ipp config. > - * > - * @ops_id: property of operation directions. > - * @flip: property of mirror, flip. > - * @degree: property of rotation degree. > - * @fmt: property of image format. > - * @sz: property of image size. > - * @pos: property of image position(src-cropped,dst-scaler). > - */ > -struct drm_exynos_ipp_config { > - __u32 ops_id; > - __u32 flip; > - __u32 degree; > - __u32 fmt; > - struct drm_exynos_sz sz; > - struct drm_exynos_pos pos; > -}; > - > -enum drm_exynos_ipp_cmd { > - IPP_CMD_NONE, > - IPP_CMD_M2M, > - IPP_CMD_WB, > - IPP_CMD_OUTPUT, > - IPP_CMD_MAX, > -}; > - > -/** > - * A structure for ipp property. > - * > - * @config: source, destination config. > - * @cmd: definition of command. > - * @ipp_id: id of ipp driver. > - * @prop_id: id of property. > - * @refresh_rate: refresh rate. > - */ > -struct drm_exynos_ipp_property { > - struct drm_exynos_ipp_config config[EXYNOS_DRM_OPS_MAX]; > - __u32 cmd; > - __u32 ipp_id; > - __u32 prop_id; > - __u32 refresh_rate; > -}; > - > -enum drm_exynos_ipp_buf_type { > - IPP_BUF_ENQUEUE, > - IPP_BUF_DEQUEUE, > -}; > - > -/** > - * A structure for ipp buffer operations. > - * > - * @ops_id: operation directions. > - * @buf_type: definition of buffer. > - * @prop_id: id of property. > - * @buf_id: id of buffer. > - * @handle: Y, Cb, Cr each planar handle. > - * @user_data: user data. > - */ > -struct drm_exynos_ipp_queue_buf { > - __u32 ops_id; > - __u32 buf_type; > - __u32 prop_id; > - __u32 buf_id; > - __u32 handle[EXYNOS_DRM_PLANAR_MAX]; > - __u32 reserved; > - __u64 user_data; > -}; > - > -enum drm_exynos_ipp_ctrl { > - IPP_CTRL_PLAY, > - IPP_CTRL_STOP, > - IPP_CTRL_PAUSE, > - IPP_CTRL_RESUME, > - IPP_CTRL_MAX, > -}; > - > -/** > - * A structure for ipp start/stop operations. > - * > - * @prop_id: id of property. > - * @ctrl: definition of control. > - */ > -struct drm_exynos_ipp_cmd_ctrl { > - __u32 prop_id; > - __u32 ctrl; > -}; > - > #define DRM_EXYNOS_GEM_CREATE 0x00 > #define DRM_EXYNOS_GEM_MAP 0x01 > /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ > @@ -311,11 +145,7 @@ struct drm_exynos_ipp_cmd_ctrl { > #define DRM_EXYNOS_G2D_SET_CMDLIST 0x21 > #define DRM_EXYNOS_G2D_EXEC 0x22 > > -/* IPP - Image Post Processing */ > -#define DRM_EXYNOS_IPP_GET_PROPERTY 0x30 > -#define DRM_EXYNOS_IPP_SET_PROPERTY 0x31 > -#define DRM_EXYNOS_IPP_QUEUE_BUF 0x32 > -#define DRM_EXYNOS_IPP_CMD_CTRL 0x33 > +/* Reserved 0x30 ~ 0x33 for obsolete Exynos IPP ioctls */ > > #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ > DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) > @@ -334,18 +164,8 @@ struct drm_exynos_ipp_cmd_ctrl { > #define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ > DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec) > > -#define DRM_IOCTL_EXYNOS_IPP_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \ > - DRM_EXYNOS_IPP_GET_PROPERTY, struct drm_exynos_ipp_prop_list) > -#define DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \ > - DRM_EXYNOS_IPP_SET_PROPERTY, struct drm_exynos_ipp_property) > -#define DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF DRM_IOWR(DRM_COMMAND_BASE + \ > - DRM_EXYNOS_IPP_QUEUE_BUF, struct drm_exynos_ipp_queue_buf) > -#define DRM_IOCTL_EXYNOS_IPP_CMD_CTRL DRM_IOWR(DRM_COMMAND_BASE + \ > - DRM_EXYNOS_IPP_CMD_CTRL, struct drm_exynos_ipp_cmd_ctrl) > - > /* EXYNOS specific events */ > #define DRM_EXYNOS_G2D_EVENT 0x80000000 > -#define DRM_EXYNOS_IPP_EVENT 0x80000001 > > struct drm_exynos_g2d_event { > struct drm_event base; > @@ -356,16 +176,6 @@ struct drm_exynos_g2d_event { > __u32 reserved; > }; > > -struct drm_exynos_ipp_event { > - struct drm_event base; > - __u64 user_data; > - __u32 tv_sec; > - __u32 tv_usec; > - __u32 prop_id; > - __u32 reserved; > - __u32 buf_id[EXYNOS_DRM_OPS_MAX]; > -}; > - > #if defined(__cplusplus) > } > #endif -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 305dc3d4ff77..88cff0e039b6 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -94,26 +94,21 @@ config DRM_EXYNOS_G2D help Choose this option if you want to use Exynos G2D for DRM. -config DRM_EXYNOS_IPP - bool "Image Post Processor" - help - Choose this option if you want to use IPP feature for DRM. - config DRM_EXYNOS_FIMC bool "FIMC" - depends on DRM_EXYNOS_IPP && MFD_SYSCON + depends on BROKEN && MFD_SYSCON help Choose this option if you want to use Exynos FIMC for DRM. config DRM_EXYNOS_ROTATOR bool "Rotator" - depends on DRM_EXYNOS_IPP + depends on BROKEN help Choose this option if you want to use Exynos Rotator for DRM. config DRM_EXYNOS_GSC bool "GScaler" - depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n + depends on BROKEN && ARCH_EXYNOS5 && VIDEO_SAMSUNG_EXYNOS_GSC=n help Choose this option if you want to use Exynos GSC for DRM. diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index f663490e949d..09bb002c9555 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -17,7 +17,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_MIXER) += exynos_mixer.o exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o -exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index b1f7299600f0..7f19054ebce3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -28,7 +28,6 @@ #include "exynos_drm_plane.h" #include "exynos_drm_vidi.h" #include "exynos_drm_g2d.h" -#include "exynos_drm_ipp.h" #include "exynos_drm_iommu.h" #define DRIVER_NAME "exynos" @@ -115,14 +114,6 @@ static void exynos_drm_lastclose(struct drm_device *dev) DRM_AUTH | DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property, - DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property, - DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf, - DRM_AUTH | DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl, - DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct file_operations exynos_drm_driver_fops = { @@ -272,9 +263,6 @@ struct exynos_drm_driver_info { }, { DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC), }, { - DRV_PTR(ipp_driver, CONFIG_DRM_EXYNOS_IPP), - DRM_VIRTUAL_DEVICE - }, { &exynos_drm_platform_driver, DRM_VIRTUAL_DEVICE } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index cf131c2aa23e..21f4271c012a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -185,7 +185,6 @@ struct exynos_drm_g2d_private { struct drm_exynos_file_private { struct exynos_drm_g2d_private *g2d_priv; - struct device *ipp_dev; }; /* @@ -292,6 +291,5 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, extern struct platform_driver fimc_driver; extern struct platform_driver rotator_driver; extern struct platform_driver gsc_driver; -extern struct platform_driver ipp_driver; extern struct platform_driver mic_driver; #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c deleted file mode 100644 index 3edda18cc2d2..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ /dev/null @@ -1,1806 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics Co.Ltd - * Authors: - * Eunchul Kim <chulspro.kim@samsung.com> - * Jinyoung Jeon <jy0.jeon@samsung.com> - * Sangmin Lee <lsmin.lee@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/types.h> -#include <linux/clk.h> -#include <linux/pm_runtime.h> - -#include <drm/drmP.h> -#include <drm/exynos_drm.h> -#include "exynos_drm_drv.h" -#include "exynos_drm_gem.h" -#include "exynos_drm_ipp.h" -#include "exynos_drm_iommu.h" - -/* - * IPP stands for Image Post Processing and - * supports image scaler/rotator and input/output DMA operations. - * using FIMC, GSC, Rotator, so on. - * IPP is integration device driver of same attribute h/w - */ - -/* - * TODO - * 1. expand command control id. - * 2. integrate property and config. - * 3. removed send_event id check routine. - * 4. compare send_event id if needed. - * 5. free subdrv_remove notifier callback list if needed. - * 6. need to check subdrv_open about multi-open. - * 7. need to power_on implement power and sysmmu ctrl. - */ - -#define get_ipp_context(dev) platform_get_drvdata(to_platform_device(dev)) -#define ipp_is_m2m_cmd(c) (c == IPP_CMD_M2M) - -/* - * A structure of event. - * - * @base: base of event. - * @event: ipp event. - */ -struct drm_exynos_ipp_send_event { - struct drm_pending_event base; - struct drm_exynos_ipp_event event; -}; - -/* - * A structure of memory node. - * - * @list: list head to memory queue information. - * @ops_id: id of operations. - * @prop_id: id of property. - * @buf_id: id of buffer. - * @buf_info: gem objects and dma address, size. - * @filp: a pointer to drm_file. - */ -struct drm_exynos_ipp_mem_node { - struct list_head list; - enum drm_exynos_ops_id ops_id; - u32 prop_id; - u32 buf_id; - struct drm_exynos_ipp_buf_info buf_info; -}; - -/* - * A structure of ipp context. - * - * @subdrv: prepare initialization using subdrv. - * @ipp_lock: lock for synchronization of access to ipp_idr. - * @prop_lock: lock for synchronization of access to prop_idr. - * @ipp_idr: ipp driver idr. - * @prop_idr: property idr. - * @event_workq: event work queue. - * @cmd_workq: command work queue. - */ -struct ipp_context { - struct exynos_drm_subdrv subdrv; - struct mutex ipp_lock; - struct mutex prop_lock; - struct idr ipp_idr; - struct idr prop_idr; - struct workqueue_struct *event_workq; - struct workqueue_struct *cmd_workq; -}; - -static LIST_HEAD(exynos_drm_ippdrv_list); -static DEFINE_MUTEX(exynos_drm_ippdrv_lock); -static BLOCKING_NOTIFIER_HEAD(exynos_drm_ippnb_list); - -int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) -{ - mutex_lock(&exynos_drm_ippdrv_lock); - list_add_tail(&ippdrv->drv_list, &exynos_drm_ippdrv_list); - mutex_unlock(&exynos_drm_ippdrv_lock); - - return 0; -} - -int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) -{ - mutex_lock(&exynos_drm_ippdrv_lock); - list_del(&ippdrv->drv_list); - mutex_unlock(&exynos_drm_ippdrv_lock); - - return 0; -} - -static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj) -{ - int ret; - - mutex_lock(lock); - ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL); - mutex_unlock(lock); - - return ret; -} - -static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id) -{ - mutex_lock(lock); - idr_remove(id_idr, id); - mutex_unlock(lock); -} - -static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id) -{ - void *obj; - - mutex_lock(lock); - obj = idr_find(id_idr, id); - mutex_unlock(lock); - - return obj; -} - -static int ipp_check_driver(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_property *property) -{ - if (ippdrv->dedicated || (!ipp_is_m2m_cmd(property->cmd) && - !pm_runtime_suspended(ippdrv->dev))) - return -EBUSY; - - if (ippdrv->check_property && - ippdrv->check_property(ippdrv->dev, property)) - return -EINVAL; - - return 0; -} - -static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx, - struct drm_exynos_ipp_property *property) -{ - struct exynos_drm_ippdrv *ippdrv; - u32 ipp_id = property->ipp_id; - int ret; - - if (ipp_id) { - ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, ipp_id); - if (!ippdrv) { - DRM_DEBUG("ipp%d driver not found\n", ipp_id); - return ERR_PTR(-ENODEV); - } - - ret = ipp_check_driver(ippdrv, property); - if (ret < 0) { - DRM_DEBUG("ipp%d driver check error %d\n", ipp_id, ret); - return ERR_PTR(ret); - } - - return ippdrv; - } else { - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - ret = ipp_check_driver(ippdrv, property); - if (ret == 0) - return ippdrv; - } - - DRM_DEBUG("cannot find driver suitable for given property.\n"); - } - - return ERR_PTR(-ENODEV); -} - -static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id) -{ - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - int count = 0; - - DRM_DEBUG_KMS("prop_id[%d]\n", prop_id); - - /* - * This case is search ipp driver by prop_id handle. - * sometimes, ipp subsystem find driver by prop_id. - * e.g PAUSE state, queue buf, command control. - */ - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n", count++, ippdrv); - - mutex_lock(&ippdrv->cmd_lock); - list_for_each_entry(c_node, &ippdrv->cmd_list, list) { - if (c_node->property.prop_id == prop_id) { - mutex_unlock(&ippdrv->cmd_lock); - return ippdrv; - } - } - mutex_unlock(&ippdrv->cmd_lock); - } - - return ERR_PTR(-ENODEV); -} - -int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_prop_list *prop_list = data; - struct exynos_drm_ippdrv *ippdrv; - int count = 0; - - if (!ctx) { - DRM_ERROR("invalid context.\n"); - return -EINVAL; - } - - if (!prop_list) { - DRM_ERROR("invalid property parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("ipp_id[%d]\n", prop_list->ipp_id); - - if (!prop_list->ipp_id) { - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) - count++; - - /* - * Supports ippdrv list count for user application. - * First step user application getting ippdrv count. - * and second step getting ippdrv capability using ipp_id. - */ - prop_list->count = count; - } else { - /* - * Getting ippdrv capability by ipp_id. - * some device not supported wb, output interface. - * so, user application detect correct ipp driver - * using this ioctl. - */ - ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock, - prop_list->ipp_id); - if (!ippdrv) { - DRM_ERROR("not found ipp%d driver.\n", - prop_list->ipp_id); - return -ENODEV; - } - - *prop_list = ippdrv->prop_list; - } - - return 0; -} - -static void ipp_print_property(struct drm_exynos_ipp_property *property, - int idx) -{ - struct drm_exynos_ipp_config *config = &property->config[idx]; - struct drm_exynos_pos *pos = &config->pos; - struct drm_exynos_sz *sz = &config->sz; - - DRM_DEBUG_KMS("prop_id[%d]ops[%s]fmt[0x%x]\n", - property->prop_id, idx ? "dst" : "src", config->fmt); - - DRM_DEBUG_KMS("pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n", - pos->x, pos->y, pos->w, pos->h, - sz->hsize, sz->vsize, config->flip, config->degree); -} - -static struct drm_exynos_ipp_cmd_work *ipp_create_cmd_work(void) -{ - struct drm_exynos_ipp_cmd_work *cmd_work; - - cmd_work = kzalloc(sizeof(*cmd_work), GFP_KERNEL); - if (!cmd_work) - return ERR_PTR(-ENOMEM); - - INIT_WORK((struct work_struct *)cmd_work, ipp_sched_cmd); - - return cmd_work; -} - -static struct drm_exynos_ipp_event_work *ipp_create_event_work(void) -{ - struct drm_exynos_ipp_event_work *event_work; - - event_work = kzalloc(sizeof(*event_work), GFP_KERNEL); - if (!event_work) - return ERR_PTR(-ENOMEM); - - INIT_WORK(&event_work->work, ipp_sched_event); - - return event_work; -} - -int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_property *property = data; - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - u32 prop_id; - int ret, i; - - if (!ctx) { - DRM_ERROR("invalid context.\n"); - return -EINVAL; - } - - if (!property) { - DRM_ERROR("invalid property parameter.\n"); - return -EINVAL; - } - - prop_id = property->prop_id; - - /* - * This is log print for user application property. - * user application set various property. - */ - for_each_ipp_ops(i) - ipp_print_property(property, i); - - /* - * In case prop_id is not zero try to set existing property. - */ - if (prop_id) { - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, prop_id); - - if (!c_node || c_node->filp != file) { - DRM_DEBUG_KMS("prop_id[%d] not found\n", prop_id); - return -EINVAL; - } - - if (c_node->state != IPP_STATE_STOP) { - DRM_DEBUG_KMS("prop_id[%d] not stopped\n", prop_id); - return -EINVAL; - } - - c_node->property = *property; - - return 0; - } - - /* find ipp driver using ipp id */ - ippdrv = ipp_find_driver(ctx, property); - if (IS_ERR(ippdrv)) { - DRM_ERROR("failed to get ipp driver.\n"); - return -EINVAL; - } - - /* allocate command node */ - c_node = kzalloc(sizeof(*c_node), GFP_KERNEL); - if (!c_node) - return -ENOMEM; - - ret = ipp_create_id(&ctx->prop_idr, &ctx->prop_lock, c_node); - if (ret < 0) { - DRM_ERROR("failed to create id.\n"); - goto err_clear; - } - property->prop_id = ret; - - DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[%pK]\n", - property->prop_id, property->cmd, ippdrv); - - /* stored property information and ippdrv in private data */ - c_node->property = *property; - c_node->state = IPP_STATE_IDLE; - c_node->filp = file; - - c_node->start_work = ipp_create_cmd_work(); - if (IS_ERR(c_node->start_work)) { - DRM_ERROR("failed to create start work.\n"); - ret = PTR_ERR(c_node->start_work); - goto err_remove_id; - } - - c_node->stop_work = ipp_create_cmd_work(); - if (IS_ERR(c_node->stop_work)) { - DRM_ERROR("failed to create stop work.\n"); - ret = PTR_ERR(c_node->stop_work); - goto err_free_start; - } - - c_node->event_work = ipp_create_event_work(); - if (IS_ERR(c_node->event_work)) { - DRM_ERROR("failed to create event work.\n"); - ret = PTR_ERR(c_node->event_work); - goto err_free_stop; - } - - mutex_init(&c_node->lock); - mutex_init(&c_node->mem_lock); - mutex_init(&c_node->event_lock); - - init_completion(&c_node->start_complete); - init_completion(&c_node->stop_complete); - - for_each_ipp_ops(i) - INIT_LIST_HEAD(&c_node->mem_list[i]); - - INIT_LIST_HEAD(&c_node->event_list); - mutex_lock(&ippdrv->cmd_lock); - list_add_tail(&c_node->list, &ippdrv->cmd_list); - mutex_unlock(&ippdrv->cmd_lock); - - /* make dedicated state without m2m */ - if (!ipp_is_m2m_cmd(property->cmd)) - ippdrv->dedicated = true; - - return 0; - -err_free_stop: - kfree(c_node->stop_work); -err_free_start: - kfree(c_node->start_work); -err_remove_id: - ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, property->prop_id); -err_clear: - kfree(c_node); - return ret; -} - -static int ipp_validate_mem_node(struct drm_device *drm_dev, - struct drm_exynos_ipp_mem_node *m_node, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct drm_exynos_ipp_config *ipp_cfg; - unsigned int num_plane; - unsigned long size, buf_size = 0, plane_size, img_size = 0; - unsigned int bpp, width, height; - int i; - - ipp_cfg = &c_node->property.config[m_node->ops_id]; - num_plane = drm_format_num_planes(ipp_cfg->fmt); - - /** - * This is a rather simplified validation of a memory node. - * It basically verifies provided gem object handles - * and the buffer sizes with respect to current configuration. - * This is not the best that can be done - * but it seems more than enough - */ - for (i = 0; i < num_plane; ++i) { - width = ipp_cfg->sz.hsize; - height = ipp_cfg->sz.vsize; - bpp = drm_format_plane_cpp(ipp_cfg->fmt, i); - - /* - * The result of drm_format_plane_cpp() for chroma planes must - * be used with drm_format_xxxx_chroma_subsampling() for - * correct result. - */ - if (i > 0) { - width /= drm_format_horz_chroma_subsampling( - ipp_cfg->fmt); - height /= drm_format_vert_chroma_subsampling( - ipp_cfg->fmt); - } - plane_size = width * height * bpp; - img_size += plane_size; - - if (m_node->buf_info.handles[i]) { - size = exynos_drm_gem_get_size(drm_dev, - m_node->buf_info.handles[i], - c_node->filp); - if (plane_size > size) { - DRM_ERROR( - "buffer %d is smaller than required\n", - i); - return -EINVAL; - } - - buf_size += size; - } - } - - if (buf_size < img_size) { - DRM_ERROR("size of buffers(%lu) is smaller than image(%lu)\n", - buf_size, img_size); - return -EINVAL; - } - - return 0; -} - -static int ipp_put_mem_node(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_mem_node *m_node) -{ - int i; - - DRM_DEBUG_KMS("node[%pK]\n", m_node); - - if (!m_node) { - DRM_ERROR("invalid dequeue node.\n"); - return -EFAULT; - } - - DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); - - /* put gem buffer */ - for_each_ipp_planar(i) { - unsigned long handle = m_node->buf_info.handles[i]; - if (handle) - exynos_drm_gem_put_dma_addr(drm_dev, handle, - c_node->filp); - } - - list_del(&m_node->list); - kfree(m_node); - - return 0; -} - -static struct drm_exynos_ipp_mem_node - *ipp_get_mem_node(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_mem_node *m_node; - struct drm_exynos_ipp_buf_info *buf_info; - int i; - - m_node = kzalloc(sizeof(*m_node), GFP_KERNEL); - if (!m_node) - return ERR_PTR(-ENOMEM); - - buf_info = &m_node->buf_info; - - /* operations, buffer id */ - m_node->ops_id = qbuf->ops_id; - m_node->prop_id = qbuf->prop_id; - m_node->buf_id = qbuf->buf_id; - INIT_LIST_HEAD(&m_node->list); - - DRM_DEBUG_KMS("m_node[%pK]ops_id[%d]\n", m_node, qbuf->ops_id); - DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id); - - for_each_ipp_planar(i) { - DRM_DEBUG_KMS("i[%d]handle[0x%x]\n", i, qbuf->handle[i]); - - /* get dma address by handle */ - if (qbuf->handle[i]) { - dma_addr_t *addr; - - addr = exynos_drm_gem_get_dma_addr(drm_dev, - qbuf->handle[i], c_node->filp); - if (IS_ERR(addr)) { - DRM_ERROR("failed to get addr.\n"); - ipp_put_mem_node(drm_dev, c_node, m_node); - return ERR_PTR(-EFAULT); - } - - buf_info->handles[i] = qbuf->handle[i]; - buf_info->base[i] = *addr; - DRM_DEBUG_KMS("i[%d]base[%pad]hd[0x%lx]\n", i, - &buf_info->base[i], buf_info->handles[i]); - } - } - - mutex_lock(&c_node->mem_lock); - if (ipp_validate_mem_node(drm_dev, m_node, c_node)) { - ipp_put_mem_node(drm_dev, c_node, m_node); - mutex_unlock(&c_node->mem_lock); - return ERR_PTR(-EFAULT); - } - list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); - mutex_unlock(&c_node->mem_lock); - - return m_node; -} - -static void ipp_clean_mem_nodes(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, int ops) -{ - struct drm_exynos_ipp_mem_node *m_node, *tm_node; - struct list_head *head = &c_node->mem_list[ops]; - - mutex_lock(&c_node->mem_lock); - - list_for_each_entry_safe(m_node, tm_node, head, list) { - int ret; - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - } - - mutex_unlock(&c_node->mem_lock); -} - -static int ipp_get_event(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_send_event *e; - int ret; - - DRM_DEBUG_KMS("ops_id[%d]buf_id[%d]\n", qbuf->ops_id, qbuf->buf_id); - - e = kzalloc(sizeof(*e), GFP_KERNEL); - if (!e) - return -ENOMEM; - - /* make event */ - e->event.base.type = DRM_EXYNOS_IPP_EVENT; - e->event.base.length = sizeof(e->event); - e->event.user_data = qbuf->user_data; - e->event.prop_id = qbuf->prop_id; - e->event.buf_id[EXYNOS_DRM_OPS_DST] = qbuf->buf_id; - - ret = drm_event_reserve_init(drm_dev, c_node->filp, &e->base, &e->event.base); - if (ret) { - kfree(e); - return ret; - } - - mutex_lock(&c_node->event_lock); - list_add_tail(&e->base.link, &c_node->event_list); - mutex_unlock(&c_node->event_lock); - - return 0; -} - -static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_send_event *e, *te; - int count = 0; - - mutex_lock(&c_node->event_lock); - list_for_each_entry_safe(e, te, &c_node->event_list, base.link) { - DRM_DEBUG_KMS("count[%d]e[%pK]\n", count++, e); - - /* - * qbuf == NULL condition means all event deletion. - * stop operations want to delete all event list. - * another case delete only same buf id. - */ - if (!qbuf) { - /* delete list */ - list_del(&e->base.link); - kfree(e); - } - - /* compare buffer id */ - if (qbuf && (qbuf->buf_id == - e->event.buf_id[EXYNOS_DRM_OPS_DST])) { - /* delete list */ - list_del(&e->base.link); - kfree(e); - goto out_unlock; - } - } - -out_unlock: - mutex_unlock(&c_node->event_lock); - return; -} - -static void ipp_clean_cmd_node(struct ipp_context *ctx, - struct drm_exynos_ipp_cmd_node *c_node) -{ - int i; - - /* cancel works */ - cancel_work_sync(&c_node->start_work->work); - cancel_work_sync(&c_node->stop_work->work); - cancel_work_sync(&c_node->event_work->work); - - /* put event */ - ipp_put_event(c_node, NULL); - - for_each_ipp_ops(i) - ipp_clean_mem_nodes(ctx->subdrv.drm_dev, c_node, i); - - /* delete list */ - list_del(&c_node->list); - - ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, - c_node->property.prop_id); - - /* destroy mutex */ - mutex_destroy(&c_node->lock); - mutex_destroy(&c_node->mem_lock); - mutex_destroy(&c_node->event_lock); - - /* free command node */ - kfree(c_node->start_work); - kfree(c_node->stop_work); - kfree(c_node->event_work); - kfree(c_node); -} - -static bool ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node) -{ - switch (c_node->property.cmd) { - case IPP_CMD_WB: - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); - case IPP_CMD_OUTPUT: - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]); - case IPP_CMD_M2M: - default: - return !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_SRC]) && - !list_empty(&c_node->mem_list[EXYNOS_DRM_OPS_DST]); - } -} - -static struct drm_exynos_ipp_mem_node - *ipp_find_mem_node(struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_mem_node *m_node; - struct list_head *head; - int count = 0; - - DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id); - - /* source/destination memory list */ - head = &c_node->mem_list[qbuf->ops_id]; - - /* find memory node from memory list */ - list_for_each_entry(m_node, head, list) { - DRM_DEBUG_KMS("count[%d]m_node[%pK]\n", count++, m_node); - - /* compare buffer id */ - if (m_node->buf_id == qbuf->buf_id) - return m_node; - } - - return NULL; -} - -static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_mem_node *m_node) -{ - struct exynos_drm_ipp_ops *ops = NULL; - int ret = 0; - - DRM_DEBUG_KMS("node[%pK]\n", m_node); - - if (!m_node) { - DRM_ERROR("invalid queue node.\n"); - return -EFAULT; - } - - DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id); - - /* get operations callback */ - ops = ippdrv->ops[m_node->ops_id]; - if (!ops) { - DRM_ERROR("not support ops.\n"); - return -EFAULT; - } - - /* set address and enable irq */ - if (ops->set_addr) { - ret = ops->set_addr(ippdrv->dev, &m_node->buf_info, - m_node->buf_id, IPP_BUF_ENQUEUE); - if (ret) { - DRM_ERROR("failed to set addr.\n"); - return ret; - } - } - - return ret; -} - -static void ipp_handle_cmd_work(struct device *dev, - struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_work *cmd_work, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct ipp_context *ctx = get_ipp_context(dev); - - cmd_work->ippdrv = ippdrv; - cmd_work->c_node = c_node; - queue_work(ctx->cmd_workq, &cmd_work->work); -} - -static int ipp_queue_buf_with_run(struct device *dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_mem_node *m_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_property *property; - struct exynos_drm_ipp_ops *ops; - int ret; - - ippdrv = ipp_find_drv_by_handle(qbuf->prop_id); - if (IS_ERR(ippdrv)) { - DRM_ERROR("failed to get ipp driver.\n"); - return -EFAULT; - } - - ops = ippdrv->ops[qbuf->ops_id]; - if (!ops) { - DRM_ERROR("failed to get ops.\n"); - return -EFAULT; - } - - property = &c_node->property; - - if (c_node->state != IPP_STATE_START) { - DRM_DEBUG_KMS("bypass for invalid state.\n"); - return 0; - } - - mutex_lock(&c_node->mem_lock); - if (!ipp_check_mem_list(c_node)) { - mutex_unlock(&c_node->mem_lock); - DRM_DEBUG_KMS("empty memory.\n"); - return 0; - } - - /* - * If set destination buffer and enabled clock, - * then m2m operations need start operations at queue_buf - */ - if (ipp_is_m2m_cmd(property->cmd)) { - struct drm_exynos_ipp_cmd_work *cmd_work = c_node->start_work; - - cmd_work->ctrl = IPP_CTRL_PLAY; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - } else { - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - mutex_unlock(&c_node->mem_lock); - DRM_ERROR("failed to set m node.\n"); - return ret; - } - } - mutex_unlock(&c_node->mem_lock); - - return 0; -} - -static void ipp_clean_queue_buf(struct drm_device *drm_dev, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_mem_node *m_node, *tm_node; - - /* delete list */ - mutex_lock(&c_node->mem_lock); - list_for_each_entry_safe(m_node, tm_node, - &c_node->mem_list[qbuf->ops_id], list) { - if (m_node->buf_id == qbuf->buf_id && - m_node->ops_id == qbuf->ops_id) - ipp_put_mem_node(drm_dev, c_node, m_node); - } - mutex_unlock(&c_node->mem_lock); -} - -int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_queue_buf *qbuf = data; - struct drm_exynos_ipp_cmd_node *c_node; - struct drm_exynos_ipp_mem_node *m_node; - int ret; - - if (!qbuf) { - DRM_ERROR("invalid buf parameter.\n"); - return -EINVAL; - } - - if (qbuf->ops_id >= EXYNOS_DRM_OPS_MAX) { - DRM_ERROR("invalid ops parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n", - qbuf->prop_id, qbuf->ops_id ? "dst" : "src", - qbuf->buf_id, qbuf->buf_type); - - /* find command node */ - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, - qbuf->prop_id); - if (!c_node || c_node->filp != file) { - DRM_ERROR("failed to get command node.\n"); - return -ENODEV; - } - - /* buffer control */ - switch (qbuf->buf_type) { - case IPP_BUF_ENQUEUE: - /* get memory node */ - m_node = ipp_get_mem_node(drm_dev, c_node, qbuf); - if (IS_ERR(m_node)) { - DRM_ERROR("failed to get m_node.\n"); - return PTR_ERR(m_node); - } - - /* - * first step get event for destination buffer. - * and second step when M2M case run with destination buffer - * if needed. - */ - if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) { - /* get event for destination buffer */ - ret = ipp_get_event(drm_dev, c_node, qbuf); - if (ret) { - DRM_ERROR("failed to get event.\n"); - goto err_clean_node; - } - - /* - * M2M case run play control for streaming feature. - * other case set address and waiting. - */ - ret = ipp_queue_buf_with_run(dev, c_node, m_node, qbuf); - if (ret) { - DRM_ERROR("failed to run command.\n"); - goto err_clean_node; - } - } - break; - case IPP_BUF_DEQUEUE: - mutex_lock(&c_node->lock); - - /* put event for destination buffer */ - if (qbuf->ops_id == EXYNOS_DRM_OPS_DST) - ipp_put_event(c_node, qbuf); - - ipp_clean_queue_buf(drm_dev, c_node, qbuf); - - mutex_unlock(&c_node->lock); - break; - default: - DRM_ERROR("invalid buffer control.\n"); - return -EINVAL; - } - - return 0; - -err_clean_node: - DRM_ERROR("clean memory nodes.\n"); - - ipp_clean_queue_buf(drm_dev, c_node, qbuf); - return ret; -} - -static bool exynos_drm_ipp_check_valid(struct device *dev, - enum drm_exynos_ipp_ctrl ctrl, enum drm_exynos_ipp_state state) -{ - if (ctrl != IPP_CTRL_PLAY) { - if (pm_runtime_suspended(dev)) { - DRM_ERROR("pm:runtime_suspended.\n"); - goto err_status; - } - } - - switch (ctrl) { - case IPP_CTRL_PLAY: - if (state != IPP_STATE_IDLE) - goto err_status; - break; - case IPP_CTRL_STOP: - if (state == IPP_STATE_STOP) - goto err_status; - break; - case IPP_CTRL_PAUSE: - if (state != IPP_STATE_START) - goto err_status; - break; - case IPP_CTRL_RESUME: - if (state != IPP_STATE_STOP) - goto err_status; - break; - default: - DRM_ERROR("invalid state.\n"); - goto err_status; - } - - return true; - -err_status: - DRM_ERROR("invalid status:ctrl[%d]state[%d]\n", ctrl, state); - return false; -} - -int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - struct exynos_drm_ippdrv *ippdrv = NULL; - struct device *dev = file_priv->ipp_dev; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_cmd_ctrl *cmd_ctrl = data; - struct drm_exynos_ipp_cmd_work *cmd_work; - struct drm_exynos_ipp_cmd_node *c_node; - - if (!ctx) { - DRM_ERROR("invalid context.\n"); - return -EINVAL; - } - - if (!cmd_ctrl) { - DRM_ERROR("invalid control parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("ctrl[%d]prop_id[%d]\n", - cmd_ctrl->ctrl, cmd_ctrl->prop_id); - - ippdrv = ipp_find_drv_by_handle(cmd_ctrl->prop_id); - if (IS_ERR(ippdrv)) { - DRM_ERROR("failed to get ipp driver.\n"); - return PTR_ERR(ippdrv); - } - - c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock, - cmd_ctrl->prop_id); - if (!c_node || c_node->filp != file) { - DRM_ERROR("invalid command node list.\n"); - return -ENODEV; - } - - if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl, - c_node->state)) { - DRM_ERROR("invalid state.\n"); - return -EINVAL; - } - - switch (cmd_ctrl->ctrl) { - case IPP_CTRL_PLAY: - if (pm_runtime_suspended(ippdrv->dev)) - pm_runtime_get_sync(ippdrv->dev); - - c_node->state = IPP_STATE_START; - - cmd_work = c_node->start_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - break; - case IPP_CTRL_STOP: - cmd_work = c_node->stop_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - - if (!wait_for_completion_timeout(&c_node->stop_complete, - msecs_to_jiffies(300))) { - DRM_ERROR("timeout stop:prop_id[%d]\n", - c_node->property.prop_id); - } - - c_node->state = IPP_STATE_STOP; - ippdrv->dedicated = false; - mutex_lock(&ippdrv->cmd_lock); - ipp_clean_cmd_node(ctx, c_node); - - if (list_empty(&ippdrv->cmd_list)) - pm_runtime_put_sync(ippdrv->dev); - mutex_unlock(&ippdrv->cmd_lock); - break; - case IPP_CTRL_PAUSE: - cmd_work = c_node->stop_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - - if (!wait_for_completion_timeout(&c_node->stop_complete, - msecs_to_jiffies(200))) { - DRM_ERROR("timeout stop:prop_id[%d]\n", - c_node->property.prop_id); - } - - c_node->state = IPP_STATE_STOP; - break; - case IPP_CTRL_RESUME: - c_node->state = IPP_STATE_START; - cmd_work = c_node->start_work; - cmd_work->ctrl = cmd_ctrl->ctrl; - ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node); - break; - default: - DRM_ERROR("could not support this state currently.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("done ctrl[%d]prop_id[%d]\n", - cmd_ctrl->ctrl, cmd_ctrl->prop_id); - - return 0; -} - -int exynos_drm_ippnb_register(struct notifier_block *nb) -{ - return blocking_notifier_chain_register( - &exynos_drm_ippnb_list, nb); -} - -int exynos_drm_ippnb_unregister(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister( - &exynos_drm_ippnb_list, nb); -} - -int exynos_drm_ippnb_send_event(unsigned long val, void *v) -{ - return blocking_notifier_call_chain( - &exynos_drm_ippnb_list, val, v); -} - -static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_property *property) -{ - struct exynos_drm_ipp_ops *ops = NULL; - bool swap = false; - int ret, i; - - if (!property) { - DRM_ERROR("invalid property parameter.\n"); - return -EINVAL; - } - - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); - - /* reset h/w block */ - if (ippdrv->reset && - ippdrv->reset(ippdrv->dev)) { - return -EINVAL; - } - - /* set source,destination operations */ - for_each_ipp_ops(i) { - struct drm_exynos_ipp_config *config = - &property->config[i]; - - ops = ippdrv->ops[i]; - if (!ops || !config) { - DRM_ERROR("not support ops and config.\n"); - return -EINVAL; - } - - /* set format */ - if (ops->set_fmt) { - ret = ops->set_fmt(ippdrv->dev, config->fmt); - if (ret) - return ret; - } - - /* set transform for rotation, flip */ - if (ops->set_transf) { - ret = ops->set_transf(ippdrv->dev, config->degree, - config->flip, &swap); - if (ret) - return ret; - } - - /* set size */ - if (ops->set_size) { - ret = ops->set_size(ippdrv->dev, swap, &config->pos, - &config->sz); - if (ret) - return ret; - } - } - - return 0; -} - -static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct drm_exynos_ipp_mem_node *m_node; - struct drm_exynos_ipp_property *property = &c_node->property; - struct list_head *head; - int ret, i; - - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); - - /* store command info in ippdrv */ - ippdrv->c_node = c_node; - - mutex_lock(&c_node->mem_lock); - if (!ipp_check_mem_list(c_node)) { - DRM_DEBUG_KMS("empty memory.\n"); - ret = -ENOMEM; - goto err_unlock; - } - - /* set current property in ippdrv */ - ret = ipp_set_property(ippdrv, property); - if (ret) { - DRM_ERROR("failed to set property.\n"); - ippdrv->c_node = NULL; - goto err_unlock; - } - - /* check command */ - switch (property->cmd) { - case IPP_CMD_M2M: - for_each_ipp_ops(i) { - /* source/destination memory list */ - head = &c_node->mem_list[i]; - - m_node = list_first_entry(head, - struct drm_exynos_ipp_mem_node, list); - - DRM_DEBUG_KMS("m_node[%pK]\n", m_node); - - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - DRM_ERROR("failed to set m node.\n"); - goto err_unlock; - } - } - break; - case IPP_CMD_WB: - /* destination memory list */ - head = &c_node->mem_list[EXYNOS_DRM_OPS_DST]; - - list_for_each_entry(m_node, head, list) { - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - DRM_ERROR("failed to set m node.\n"); - goto err_unlock; - } - } - break; - case IPP_CMD_OUTPUT: - /* source memory list */ - head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; - - list_for_each_entry(m_node, head, list) { - ret = ipp_set_mem_node(ippdrv, c_node, m_node); - if (ret) { - DRM_ERROR("failed to set m node.\n"); - goto err_unlock; - } - } - break; - default: - DRM_ERROR("invalid operations.\n"); - ret = -EINVAL; - goto err_unlock; - } - mutex_unlock(&c_node->mem_lock); - - DRM_DEBUG_KMS("cmd[%d]\n", property->cmd); - - /* start operations */ - if (ippdrv->start) { - ret = ippdrv->start(ippdrv->dev, property->cmd); - if (ret) { - DRM_ERROR("failed to start ops.\n"); - ippdrv->c_node = NULL; - return ret; - } - } - - return 0; - -err_unlock: - mutex_unlock(&c_node->mem_lock); - ippdrv->c_node = NULL; - return ret; -} - -static int ipp_stop_property(struct drm_device *drm_dev, - struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node) -{ - struct drm_exynos_ipp_property *property = &c_node->property; - int i; - - DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id); - - /* stop operations */ - if (ippdrv->stop) - ippdrv->stop(ippdrv->dev, property->cmd); - - /* check command */ - switch (property->cmd) { - case IPP_CMD_M2M: - for_each_ipp_ops(i) - ipp_clean_mem_nodes(drm_dev, c_node, i); - break; - case IPP_CMD_WB: - ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_DST); - break; - case IPP_CMD_OUTPUT: - ipp_clean_mem_nodes(drm_dev, c_node, EXYNOS_DRM_OPS_SRC); - break; - default: - DRM_ERROR("invalid operations.\n"); - return -EINVAL; - } - - return 0; -} - -void ipp_sched_cmd(struct work_struct *work) -{ - struct drm_exynos_ipp_cmd_work *cmd_work = - container_of(work, struct drm_exynos_ipp_cmd_work, work); - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - struct drm_exynos_ipp_property *property; - int ret; - - ippdrv = cmd_work->ippdrv; - if (!ippdrv) { - DRM_ERROR("invalid ippdrv list.\n"); - return; - } - - c_node = cmd_work->c_node; - if (!c_node) { - DRM_ERROR("invalid command node list.\n"); - return; - } - - mutex_lock(&c_node->lock); - - property = &c_node->property; - - switch (cmd_work->ctrl) { - case IPP_CTRL_PLAY: - case IPP_CTRL_RESUME: - ret = ipp_start_property(ippdrv, c_node); - if (ret) { - DRM_ERROR("failed to start property:prop_id[%d]\n", - c_node->property.prop_id); - goto err_unlock; - } - - /* - * M2M case supports wait_completion of transfer. - * because M2M case supports single unit operation - * with multiple queue. - * M2M need to wait completion of data transfer. - */ - if (ipp_is_m2m_cmd(property->cmd)) { - if (!wait_for_completion_timeout - (&c_node->start_complete, msecs_to_jiffies(200))) { - DRM_ERROR("timeout event:prop_id[%d]\n", - c_node->property.prop_id); - goto err_unlock; - } - } - break; - case IPP_CTRL_STOP: - case IPP_CTRL_PAUSE: - ret = ipp_stop_property(ippdrv->drm_dev, ippdrv, - c_node); - if (ret) { - DRM_ERROR("failed to stop property.\n"); - goto err_unlock; - } - - complete(&c_node->stop_complete); - break; - default: - DRM_ERROR("unknown control type\n"); - break; - } - - DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl); - -err_unlock: - mutex_unlock(&c_node->lock); -} - -static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv, - struct drm_exynos_ipp_cmd_node *c_node, int *buf_id) -{ - struct drm_device *drm_dev = ippdrv->drm_dev; - struct drm_exynos_ipp_property *property = &c_node->property; - struct drm_exynos_ipp_mem_node *m_node; - struct drm_exynos_ipp_queue_buf qbuf; - struct drm_exynos_ipp_send_event *e; - struct list_head *head; - struct timeval now; - u32 tbuf_id[EXYNOS_DRM_OPS_MAX] = {0, }; - int ret, i; - - for_each_ipp_ops(i) - DRM_DEBUG_KMS("%s buf_id[%d]\n", i ? "dst" : "src", buf_id[i]); - - if (!drm_dev) { - DRM_ERROR("failed to get drm_dev.\n"); - return -EINVAL; - } - - if (!property) { - DRM_ERROR("failed to get property.\n"); - return -EINVAL; - } - - mutex_lock(&c_node->event_lock); - if (list_empty(&c_node->event_list)) { - DRM_DEBUG_KMS("event list is empty.\n"); - ret = 0; - goto err_event_unlock; - } - - mutex_lock(&c_node->mem_lock); - if (!ipp_check_mem_list(c_node)) { - DRM_DEBUG_KMS("empty memory.\n"); - ret = 0; - goto err_mem_unlock; - } - - /* check command */ - switch (property->cmd) { - case IPP_CMD_M2M: - for_each_ipp_ops(i) { - /* source/destination memory list */ - head = &c_node->mem_list[i]; - - m_node = list_first_entry(head, - struct drm_exynos_ipp_mem_node, list); - - tbuf_id[i] = m_node->buf_id; - DRM_DEBUG_KMS("%s buf_id[%d]\n", - i ? "dst" : "src", tbuf_id[i]); - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - } - break; - case IPP_CMD_WB: - /* clear buf for finding */ - memset(&qbuf, 0x0, sizeof(qbuf)); - qbuf.ops_id = EXYNOS_DRM_OPS_DST; - qbuf.buf_id = buf_id[EXYNOS_DRM_OPS_DST]; - - /* get memory node entry */ - m_node = ipp_find_mem_node(c_node, &qbuf); - if (!m_node) { - DRM_ERROR("empty memory node.\n"); - ret = -ENOMEM; - goto err_mem_unlock; - } - - tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id; - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - break; - case IPP_CMD_OUTPUT: - /* source memory list */ - head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC]; - - m_node = list_first_entry(head, - struct drm_exynos_ipp_mem_node, list); - - tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id; - - ret = ipp_put_mem_node(drm_dev, c_node, m_node); - if (ret) - DRM_ERROR("failed to put m_node.\n"); - break; - default: - DRM_ERROR("invalid operations.\n"); - ret = -EINVAL; - goto err_mem_unlock; - } - mutex_unlock(&c_node->mem_lock); - - if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST]) - DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n", - tbuf_id[1], buf_id[1], property->prop_id); - - /* - * command node have event list of destination buffer - * If destination buffer enqueue to mem list, - * then we make event and link to event list tail. - * so, we get first event for first enqueued buffer. - */ - e = list_first_entry(&c_node->event_list, - struct drm_exynos_ipp_send_event, base.link); - - do_gettimeofday(&now); - DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec); - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; - e->event.prop_id = property->prop_id; - - /* set buffer id about source destination */ - for_each_ipp_ops(i) - e->event.buf_id[i] = tbuf_id[i]; - - drm_send_event(drm_dev, &e->base); - mutex_unlock(&c_node->event_lock); - - DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n", - property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]); - - return 0; - -err_mem_unlock: - mutex_unlock(&c_node->mem_lock); -err_event_unlock: - mutex_unlock(&c_node->event_lock); - return ret; -} - -void ipp_sched_event(struct work_struct *work) -{ - struct drm_exynos_ipp_event_work *event_work = - container_of(work, struct drm_exynos_ipp_event_work, work); - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - int ret; - - if (!event_work) { - DRM_ERROR("failed to get event_work.\n"); - return; - } - - DRM_DEBUG_KMS("buf_id[%d]\n", event_work->buf_id[EXYNOS_DRM_OPS_DST]); - - ippdrv = event_work->ippdrv; - if (!ippdrv) { - DRM_ERROR("failed to get ipp driver.\n"); - return; - } - - c_node = ippdrv->c_node; - if (!c_node) { - DRM_ERROR("failed to get command node.\n"); - return; - } - - /* - * IPP supports command thread, event thread synchronization. - * If IPP close immediately from user land, then IPP make - * synchronization with command thread, so make complete event. - * or going out operations. - */ - if (c_node->state != IPP_STATE_START) { - DRM_DEBUG_KMS("bypass state[%d]prop_id[%d]\n", - c_node->state, c_node->property.prop_id); - goto err_completion; - } - - ret = ipp_send_event(ippdrv, c_node, event_work->buf_id); - if (ret) { - DRM_ERROR("failed to send event.\n"); - goto err_completion; - } - -err_completion: - if (ipp_is_m2m_cmd(c_node->property.cmd)) - complete(&c_node->start_complete); -} - -static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev) -{ - struct ipp_context *ctx = get_ipp_context(dev); - struct exynos_drm_ippdrv *ippdrv; - int ret, count = 0; - - /* get ipp driver entry */ - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - ippdrv->drm_dev = drm_dev; - - ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv); - if (ret < 0) { - DRM_ERROR("failed to create id.\n"); - goto err; - } - ippdrv->prop_list.ipp_id = ret; - - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]ipp_id[%d]\n", - count++, ippdrv, ret); - - /* store parent device for node */ - ippdrv->parent_dev = dev; - - /* store event work queue and handler */ - ippdrv->event_workq = ctx->event_workq; - ippdrv->sched_event = ipp_sched_event; - INIT_LIST_HEAD(&ippdrv->cmd_list); - mutex_init(&ippdrv->cmd_lock); - - ret = drm_iommu_attach_device(drm_dev, ippdrv->dev); - if (ret) { - DRM_ERROR("failed to activate iommu\n"); - goto err; - } - } - - return 0; - -err: - /* get ipp driver entry */ - list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list, - drv_list) { - drm_iommu_detach_device(drm_dev, ippdrv->dev); - - ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, - ippdrv->prop_list.ipp_id); - } - - return ret; -} - -static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev) -{ - struct exynos_drm_ippdrv *ippdrv, *t; - struct ipp_context *ctx = get_ipp_context(dev); - - /* get ipp driver entry */ - list_for_each_entry_safe(ippdrv, t, &exynos_drm_ippdrv_list, drv_list) { - drm_iommu_detach_device(drm_dev, ippdrv->dev); - - ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock, - ippdrv->prop_list.ipp_id); - - ippdrv->drm_dev = NULL; - exynos_drm_ippdrv_unregister(ippdrv); - } -} - -static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file) -{ - struct drm_exynos_file_private *file_priv = file->driver_priv; - - file_priv->ipp_dev = dev; - - DRM_DEBUG_KMS("done priv[%pK]\n", dev); - - return 0; -} - -static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev, - struct drm_file *file) -{ - struct exynos_drm_ippdrv *ippdrv = NULL; - struct ipp_context *ctx = get_ipp_context(dev); - struct drm_exynos_ipp_cmd_node *c_node, *tc_node; - int count = 0; - - list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) { - mutex_lock(&ippdrv->cmd_lock); - list_for_each_entry_safe(c_node, tc_node, - &ippdrv->cmd_list, list) { - DRM_DEBUG_KMS("count[%d]ippdrv[%pK]\n", - count++, ippdrv); - - if (c_node->filp == file) { - /* - * userland goto unnormal state. process killed. - * and close the file. - * so, IPP didn't called stop cmd ctrl. - * so, we are make stop operation in this state. - */ - if (c_node->state == IPP_STATE_START) { - ipp_stop_property(drm_dev, ippdrv, - c_node); - c_node->state = IPP_STATE_STOP; - } - - ippdrv->dedicated = false; - ipp_clean_cmd_node(ctx, c_node); - if (list_empty(&ippdrv->cmd_list)) - pm_runtime_put_sync(ippdrv->dev); - } - } - mutex_unlock(&ippdrv->cmd_lock); - } - - return; -} - -static int ipp_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct ipp_context *ctx; - struct exynos_drm_subdrv *subdrv; - int ret; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - mutex_init(&ctx->ipp_lock); - mutex_init(&ctx->prop_lock); - - idr_init(&ctx->ipp_idr); - idr_init(&ctx->prop_idr); - - /* - * create single thread for ipp event - * IPP supports event thread for IPP drivers. - * IPP driver send event_work to this thread. - * and IPP event thread send event to user process. - */ - ctx->event_workq = create_singlethread_workqueue("ipp_event"); - if (!ctx->event_workq) { - dev_err(dev, "failed to create event workqueue\n"); - return -EINVAL; - } - - /* - * create single thread for ipp command - * IPP supports command thread for user process. - * user process make command node using set property ioctl. - * and make start_work and send this work to command thread. - * and then this command thread start property. - */ - ctx->cmd_workq = create_singlethread_workqueue("ipp_cmd"); - if (!ctx->cmd_workq) { - dev_err(dev, "failed to create cmd workqueue\n"); - ret = -EINVAL; - goto err_event_workq; - } - - /* set sub driver informations */ - subdrv = &ctx->subdrv; - subdrv->dev = dev; - subdrv->probe = ipp_subdrv_probe; - subdrv->remove = ipp_subdrv_remove; - subdrv->open = ipp_subdrv_open; - subdrv->close = ipp_subdrv_close; - - platform_set_drvdata(pdev, ctx); - - ret = exynos_drm_subdrv_register(subdrv); - if (ret < 0) { - DRM_ERROR("failed to register drm ipp device.\n"); - goto err_cmd_workq; - } - - dev_info(dev, "drm ipp registered successfully.\n"); - - return 0; - -err_cmd_workq: - destroy_workqueue(ctx->cmd_workq); -err_event_workq: - destroy_workqueue(ctx->event_workq); - return ret; -} - -static int ipp_remove(struct platform_device *pdev) -{ - struct ipp_context *ctx = platform_get_drvdata(pdev); - - /* unregister sub driver */ - exynos_drm_subdrv_unregister(&ctx->subdrv); - - /* remove,destroy ipp idr */ - idr_destroy(&ctx->ipp_idr); - idr_destroy(&ctx->prop_idr); - - mutex_destroy(&ctx->ipp_lock); - mutex_destroy(&ctx->prop_lock); - - /* destroy command, event work queue */ - destroy_workqueue(ctx->cmd_workq); - destroy_workqueue(ctx->event_workq); - - return 0; -} - -struct platform_driver ipp_driver = { - .probe = ipp_probe, - .remove = ipp_remove, - .driver = { - .name = "exynos-drm-ipp", - .owner = THIS_MODULE, - }, -}; - diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.h b/drivers/gpu/drm/exynos/exynos_drm_ipp.h deleted file mode 100644 index 2a61547a39d0..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * - * Authors: - * Eunchul Kim <chulspro.kim@samsung.com> - * Jinyoung Jeon <jy0.jeon@samsung.com> - * Sangmin Lee <lsmin.lee@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef _EXYNOS_DRM_IPP_H_ -#define _EXYNOS_DRM_IPP_H_ - -#define for_each_ipp_ops(pos) \ - for (pos = 0; pos < EXYNOS_DRM_OPS_MAX; pos++) -#define for_each_ipp_planar(pos) \ - for (pos = 0; pos < EXYNOS_DRM_PLANAR_MAX; pos++) - -#define IPP_GET_LCD_WIDTH _IOR('F', 302, int) -#define IPP_GET_LCD_HEIGHT _IOR('F', 303, int) -#define IPP_SET_WRITEBACK _IOW('F', 304, u32) - -/* definition of state */ -enum drm_exynos_ipp_state { - IPP_STATE_IDLE, - IPP_STATE_START, - IPP_STATE_STOP, -}; - -/* - * A structure of command work information. - * @work: work structure. - * @ippdrv: current work ippdrv. - * @c_node: command node information. - * @ctrl: command control. - */ -struct drm_exynos_ipp_cmd_work { - struct work_struct work; - struct exynos_drm_ippdrv *ippdrv; - struct drm_exynos_ipp_cmd_node *c_node; - enum drm_exynos_ipp_ctrl ctrl; -}; - -/* - * A structure of command node. - * - * @list: list head to command queue information. - * @event_list: list head of event. - * @mem_list: list head to source,destination memory queue information. - * @lock: lock for synchronization of access to ioctl. - * @mem_lock: lock for synchronization of access to memory nodes. - * @event_lock: lock for synchronization of access to scheduled event. - * @start_complete: completion of start of command. - * @stop_complete: completion of stop of command. - * @property: property information. - * @start_work: start command work structure. - * @stop_work: stop command work structure. - * @event_work: event work structure. - * @state: state of command node. - * @filp: associated file pointer. - */ -struct drm_exynos_ipp_cmd_node { - struct list_head list; - struct list_head event_list; - struct list_head mem_list[EXYNOS_DRM_OPS_MAX]; - struct mutex lock; - struct mutex mem_lock; - struct mutex event_lock; - struct completion start_complete; - struct completion stop_complete; - struct drm_exynos_ipp_property property; - struct drm_exynos_ipp_cmd_work *start_work; - struct drm_exynos_ipp_cmd_work *stop_work; - struct drm_exynos_ipp_event_work *event_work; - enum drm_exynos_ipp_state state; - struct drm_file *filp; -}; - -/* - * A structure of buffer information. - * - * @handles: Y, Cb, Cr each gem object handle. - * @base: Y, Cb, Cr each planar address. - */ -struct drm_exynos_ipp_buf_info { - unsigned long handles[EXYNOS_DRM_PLANAR_MAX]; - dma_addr_t base[EXYNOS_DRM_PLANAR_MAX]; -}; - -/* - * A structure of wb setting information. - * - * @enable: enable flag for wb. - * @refresh: HZ of the refresh rate. - */ -struct drm_exynos_ipp_set_wb { - __u32 enable; - __u32 refresh; -}; - -/* - * A structure of event work information. - * - * @work: work structure. - * @ippdrv: current work ippdrv. - * @buf_id: id of src, dst buffer. - */ -struct drm_exynos_ipp_event_work { - struct work_struct work; - struct exynos_drm_ippdrv *ippdrv; - u32 buf_id[EXYNOS_DRM_OPS_MAX]; -}; - -/* - * A structure of source,destination operations. - * - * @set_fmt: set format of image. - * @set_transf: set transform(rotations, flip). - * @set_size: set size of region. - * @set_addr: set address for dma. - */ -struct exynos_drm_ipp_ops { - int (*set_fmt)(struct device *dev, u32 fmt); - int (*set_transf)(struct device *dev, - enum drm_exynos_degree degree, - enum drm_exynos_flip flip, bool *swap); - int (*set_size)(struct device *dev, int swap, - struct drm_exynos_pos *pos, struct drm_exynos_sz *sz); - int (*set_addr)(struct device *dev, - struct drm_exynos_ipp_buf_info *buf_info, u32 buf_id, - enum drm_exynos_ipp_buf_type buf_type); -}; - -/* - * A structure of ipp driver. - * - * @drv_list: list head for registed sub driver information. - * @parent_dev: parent device information. - * @dev: platform device. - * @drm_dev: drm device. - * @dedicated: dedicated ipp device. - * @ops: source, destination operations. - * @event_workq: event work queue. - * @c_node: current command information. - * @cmd_list: list head for command information. - * @cmd_lock: lock for synchronization of access to cmd_list. - * @prop_list: property informations of current ipp driver. - * @check_property: check property about format, size, buffer. - * @reset: reset ipp block. - * @start: ipp each device start. - * @stop: ipp each device stop. - * @sched_event: work schedule handler. - */ -struct exynos_drm_ippdrv { - struct list_head drv_list; - struct device *parent_dev; - struct device *dev; - struct drm_device *drm_dev; - bool dedicated; - struct exynos_drm_ipp_ops *ops[EXYNOS_DRM_OPS_MAX]; - struct workqueue_struct *event_workq; - struct drm_exynos_ipp_cmd_node *c_node; - struct list_head cmd_list; - struct mutex cmd_lock; - struct drm_exynos_ipp_prop_list prop_list; - - int (*check_property)(struct device *dev, - struct drm_exynos_ipp_property *property); - int (*reset)(struct device *dev); - int (*start)(struct device *dev, enum drm_exynos_ipp_cmd cmd); - void (*stop)(struct device *dev, enum drm_exynos_ipp_cmd cmd); - void (*sched_event)(struct work_struct *work); -}; - -#ifdef CONFIG_DRM_EXYNOS_IPP -extern int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv); -extern int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv); -extern int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data, - struct drm_file *file); -extern int exynos_drm_ippnb_register(struct notifier_block *nb); -extern int exynos_drm_ippnb_unregister(struct notifier_block *nb); -extern int exynos_drm_ippnb_send_event(unsigned long val, void *v); -extern void ipp_sched_cmd(struct work_struct *work); -extern void ipp_sched_event(struct work_struct *work); - -#else -static inline int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv) -{ - return -ENODEV; -} - -static inline int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv) -{ - return -ENODEV; -} - -static inline int exynos_drm_ipp_get_property(struct drm_device *drm_dev, - void *data, - struct drm_file *file_priv) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ipp_set_property(struct drm_device *drm_dev, - void *data, - struct drm_file *file_priv) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, - void *data, - struct drm_file *file) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, - void *data, - struct drm_file *file) -{ - return -ENOTTY; -} - -static inline int exynos_drm_ippnb_register(struct notifier_block *nb) -{ - return -ENODEV; -} - -static inline int exynos_drm_ippnb_unregister(struct notifier_block *nb) -{ - return -ENODEV; -} - -static inline int exynos_drm_ippnb_send_event(unsigned long val, void *v) -{ - return -ENOTTY; -} -#endif - -#endif /* _EXYNOS_DRM_IPP_H_ */ - diff --git a/include/uapi/drm/exynos_drm.h b/include/uapi/drm/exynos_drm.h index cb3e9f9d029f..544db2cecb36 100644 --- a/include/uapi/drm/exynos_drm.h +++ b/include/uapi/drm/exynos_drm.h @@ -134,172 +134,6 @@ struct drm_exynos_g2d_exec { __u64 async; }; -enum drm_exynos_ops_id { - EXYNOS_DRM_OPS_SRC, - EXYNOS_DRM_OPS_DST, - EXYNOS_DRM_OPS_MAX, -}; - -struct drm_exynos_sz { - __u32 hsize; - __u32 vsize; -}; - -struct drm_exynos_pos { - __u32 x; - __u32 y; - __u32 w; - __u32 h; -}; - -enum drm_exynos_flip { - EXYNOS_DRM_FLIP_NONE = (0 << 0), - EXYNOS_DRM_FLIP_VERTICAL = (1 << 0), - EXYNOS_DRM_FLIP_HORIZONTAL = (1 << 1), - EXYNOS_DRM_FLIP_BOTH = EXYNOS_DRM_FLIP_VERTICAL | - EXYNOS_DRM_FLIP_HORIZONTAL, -}; - -enum drm_exynos_degree { - EXYNOS_DRM_DEGREE_0, - EXYNOS_DRM_DEGREE_90, - EXYNOS_DRM_DEGREE_180, - EXYNOS_DRM_DEGREE_270, -}; - -enum drm_exynos_planer { - EXYNOS_DRM_PLANAR_Y, - EXYNOS_DRM_PLANAR_CB, - EXYNOS_DRM_PLANAR_CR, - EXYNOS_DRM_PLANAR_MAX, -}; - -/** - * A structure for ipp supported property list. - * - * @version: version of this structure. - * @ipp_id: id of ipp driver. - * @count: count of ipp driver. - * @writeback: flag of writeback supporting. - * @flip: flag of flip supporting. - * @degree: flag of degree information. - * @csc: flag of csc supporting. - * @crop: flag of crop supporting. - * @scale: flag of scale supporting. - * @refresh_min: min hz of refresh. - * @refresh_max: max hz of refresh. - * @crop_min: crop min resolution. - * @crop_max: crop max resolution. - * @scale_min: scale min resolution. - * @scale_max: scale max resolution. - */ -struct drm_exynos_ipp_prop_list { - __u32 version; - __u32 ipp_id; - __u32 count; - __u32 writeback; - __u32 flip; - __u32 degree; - __u32 csc; - __u32 crop; - __u32 scale; - __u32 refresh_min; - __u32 refresh_max; - __u32 reserved; - struct drm_exynos_sz crop_min; - struct drm_exynos_sz crop_max; - struct drm_exynos_sz scale_min; - struct drm_exynos_sz scale_max; -}; - -/** - * A structure for ipp config. - * - * @ops_id: property of operation directions. - * @flip: property of mirror, flip. - * @degree: property of rotation degree. - * @fmt: property of image format. - * @sz: property of image size. - * @pos: property of image position(src-cropped,dst-scaler). - */ -struct drm_exynos_ipp_config { - __u32 ops_id; - __u32 flip; - __u32 degree; - __u32 fmt; - struct drm_exynos_sz sz; - struct drm_exynos_pos pos; -}; - -enum drm_exynos_ipp_cmd { - IPP_CMD_NONE, - IPP_CMD_M2M, - IPP_CMD_WB, - IPP_CMD_OUTPUT, - IPP_CMD_MAX, -}; - -/** - * A structure for ipp property. - * - * @config: source, destination config. - * @cmd: definition of command. - * @ipp_id: id of ipp driver. - * @prop_id: id of property. - * @refresh_rate: refresh rate. - */ -struct drm_exynos_ipp_property { - struct drm_exynos_ipp_config config[EXYNOS_DRM_OPS_MAX]; - __u32 cmd; - __u32 ipp_id; - __u32 prop_id; - __u32 refresh_rate; -}; - -enum drm_exynos_ipp_buf_type { - IPP_BUF_ENQUEUE, - IPP_BUF_DEQUEUE, -}; - -/** - * A structure for ipp buffer operations. - * - * @ops_id: operation directions. - * @buf_type: definition of buffer. - * @prop_id: id of property. - * @buf_id: id of buffer. - * @handle: Y, Cb, Cr each planar handle. - * @user_data: user data. - */ -struct drm_exynos_ipp_queue_buf { - __u32 ops_id; - __u32 buf_type; - __u32 prop_id; - __u32 buf_id; - __u32 handle[EXYNOS_DRM_PLANAR_MAX]; - __u32 reserved; - __u64 user_data; -}; - -enum drm_exynos_ipp_ctrl { - IPP_CTRL_PLAY, - IPP_CTRL_STOP, - IPP_CTRL_PAUSE, - IPP_CTRL_RESUME, - IPP_CTRL_MAX, -}; - -/** - * A structure for ipp start/stop operations. - * - * @prop_id: id of property. - * @ctrl: definition of control. - */ -struct drm_exynos_ipp_cmd_ctrl { - __u32 prop_id; - __u32 ctrl; -}; - #define DRM_EXYNOS_GEM_CREATE 0x00 #define DRM_EXYNOS_GEM_MAP 0x01 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ @@ -311,11 +145,7 @@ struct drm_exynos_ipp_cmd_ctrl { #define DRM_EXYNOS_G2D_SET_CMDLIST 0x21 #define DRM_EXYNOS_G2D_EXEC 0x22 -/* IPP - Image Post Processing */ -#define DRM_EXYNOS_IPP_GET_PROPERTY 0x30 -#define DRM_EXYNOS_IPP_SET_PROPERTY 0x31 -#define DRM_EXYNOS_IPP_QUEUE_BUF 0x32 -#define DRM_EXYNOS_IPP_CMD_CTRL 0x33 +/* Reserved 0x30 ~ 0x33 for obsolete Exynos IPP ioctls */ #define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) @@ -334,18 +164,8 @@ struct drm_exynos_ipp_cmd_ctrl { #define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec) -#define DRM_IOCTL_EXYNOS_IPP_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_GET_PROPERTY, struct drm_exynos_ipp_prop_list) -#define DRM_IOCTL_EXYNOS_IPP_SET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_SET_PROPERTY, struct drm_exynos_ipp_property) -#define DRM_IOCTL_EXYNOS_IPP_QUEUE_BUF DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_QUEUE_BUF, struct drm_exynos_ipp_queue_buf) -#define DRM_IOCTL_EXYNOS_IPP_CMD_CTRL DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_IPP_CMD_CTRL, struct drm_exynos_ipp_cmd_ctrl) - /* EXYNOS specific events */ #define DRM_EXYNOS_G2D_EVENT 0x80000000 -#define DRM_EXYNOS_IPP_EVENT 0x80000001 struct drm_exynos_g2d_event { struct drm_event base; @@ -356,16 +176,6 @@ struct drm_exynos_g2d_event { __u32 reserved; }; -struct drm_exynos_ipp_event { - struct drm_event base; - __u64 user_data; - __u32 tv_sec; - __u32 tv_usec; - __u32 prop_id; - __u32 reserved; - __u32 buf_id[EXYNOS_DRM_OPS_MAX]; -}; - #if defined(__cplusplus) } #endif
Exynos IPP will be rewritten, so remove current IPP core code and mark existing drivers as BROKEN. Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> --- drivers/gpu/drm/exynos/Kconfig | 11 +- drivers/gpu/drm/exynos/Makefile | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.c | 12 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 - drivers/gpu/drm/exynos/exynos_drm_ipp.c | 1806 ------------------------------- drivers/gpu/drm/exynos/exynos_drm_ipp.h | 252 ----- include/uapi/drm/exynos_drm.h | 192 +--- 7 files changed, 4 insertions(+), 2272 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_ipp.c delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_ipp.h -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html