Merge tag 'exynos-drm-next-for-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Cleanups - Change g2d driver to component based driver . g2d driver was last customed sub driver so this patch series changes it to component based driver, which also makes gem handling to be more simplify. - Cleanup of Exynos DRM suspend/resume . Register exynos drm core suspend/resume functions to prepare/complete callbacks of dev_pm_ops instead of suspend/resume callbacks to ensure exynos_drm_suspend() is called before any suspend callback from the real devices to avoid some issues on boards with complex pipelines. . Also Add pm_runtime_furce_suspend/resume as SYSTEM_SLEEP_PM_OPS to ensure that resources of each devices will be released for the system PM suspend/resume cycle. - Remove local value not used. Signed-off-by: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/1532505748-10025-1-git-send-email-inki.dae@samsung.com
This commit is contained in:
@ -4,7 +4,7 @@
|
|||||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||||
|
|
||||||
exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \
|
exynosdrm-y := exynos_drm_drv.o exynos_drm_crtc.o exynos_drm_fb.o \
|
||||||
exynos_drm_gem.o exynos_drm_core.o exynos_drm_plane.o
|
exynos_drm_gem.o exynos_drm_plane.o
|
||||||
|
|
||||||
exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
|
exynosdrm-$(CONFIG_DRM_FBDEV_EMULATION) += exynos_drm_fbdev.o
|
||||||
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
|
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
|
||||||
|
@ -265,7 +265,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
|||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
||||||
val = readl(ctx->addr + DECON_WINCONx(win));
|
val = readl(ctx->addr + DECON_WINCONx(win));
|
||||||
val &= ~WINCONx_BPPMODE_MASK;
|
val &= WINCONx_ENWIN_F;
|
||||||
|
|
||||||
switch (fb->format->format) {
|
switch (fb->format->format) {
|
||||||
case DRM_FORMAT_XRGB1555:
|
case DRM_FORMAT_XRGB1555:
|
||||||
@ -356,8 +356,8 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
|
|||||||
writel(val, ctx->addr + DECON_VIDOSDxB(win));
|
writel(val, ctx->addr + DECON_VIDOSDxB(win));
|
||||||
}
|
}
|
||||||
|
|
||||||
val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
|
val = VIDOSD_Wx_ALPHA_R_F(0xff) | VIDOSD_Wx_ALPHA_G_F(0xff) |
|
||||||
VIDOSD_Wx_ALPHA_B_F(0x0);
|
VIDOSD_Wx_ALPHA_B_F(0xff);
|
||||||
writel(val, ctx->addr + DECON_VIDOSDxC(win));
|
writel(val, ctx->addr + DECON_VIDOSDxC(win));
|
||||||
|
|
||||||
val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
|
val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) |
|
||||||
@ -673,6 +673,8 @@ err:
|
|||||||
static const struct dev_pm_ops exynos5433_decon_pm_ops = {
|
static const struct dev_pm_ops exynos5433_decon_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume,
|
SET_RUNTIME_PM_OPS(exynos5433_decon_suspend, exynos5433_decon_resume,
|
||||||
NULL)
|
NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
|
static const struct of_device_id exynos5433_decon_driver_dt_match[] = {
|
||||||
|
@ -832,6 +832,8 @@ static int exynos7_decon_resume(struct device *dev)
|
|||||||
static const struct dev_pm_ops exynos7_decon_pm_ops = {
|
static const struct dev_pm_ops exynos7_decon_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume,
|
SET_RUNTIME_PM_OPS(exynos7_decon_suspend, exynos7_decon_resume,
|
||||||
NULL)
|
NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_driver decon_driver = {
|
struct platform_driver decon_driver = {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/of_graph.h>
|
#include <linux/of_graph.h>
|
||||||
#include <linux/component.h>
|
#include <linux/component.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <video/of_display_timing.h>
|
#include <video/of_display_timing.h>
|
||||||
#include <video/of_videomode.h>
|
#include <video/of_videomode.h>
|
||||||
#include <video/videomode.h>
|
#include <video/videomode.h>
|
||||||
@ -278,6 +279,8 @@ static int exynos_dp_resume(struct device *dev)
|
|||||||
|
|
||||||
static const struct dev_pm_ops exynos_dp_pm_ops = {
|
static const struct dev_pm_ops exynos_dp_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL)
|
SET_RUNTIME_PM_OPS(exynos_dp_suspend, exynos_dp_resume, NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id exynos_dp_match[] = {
|
static const struct of_device_id exynos_dp_match[] = {
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
/* exynos_drm_core.c
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
|
||||||
* Author:
|
|
||||||
* Inki Dae <inki.dae@samsung.com>
|
|
||||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
|
||||||
* Seung-Woo Kim <sw0312.kim@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 <drm/drmP.h>
|
|
||||||
|
|
||||||
#include "exynos_drm_drv.h"
|
|
||||||
#include "exynos_drm_crtc.h"
|
|
||||||
|
|
||||||
static LIST_HEAD(exynos_drm_subdrv_list);
|
|
||||||
|
|
||||||
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
|
|
||||||
{
|
|
||||||
if (!subdrv)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
|
|
||||||
{
|
|
||||||
if (!subdrv)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
list_del(&subdrv->list);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exynos_drm_device_subdrv_probe(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct exynos_drm_subdrv *subdrv, *n;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!dev)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
|
|
||||||
if (subdrv->probe) {
|
|
||||||
subdrv->drm_dev = dev;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* this probe callback would be called by sub driver
|
|
||||||
* after setting of all resources to this sub driver,
|
|
||||||
* such as clock, irq and register map are done.
|
|
||||||
*/
|
|
||||||
err = subdrv->probe(dev, subdrv->dev);
|
|
||||||
if (err) {
|
|
||||||
DRM_DEBUG("exynos drm subdrv probe failed.\n");
|
|
||||||
list_del(&subdrv->list);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exynos_drm_device_subdrv_remove(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct exynos_drm_subdrv *subdrv;
|
|
||||||
|
|
||||||
if (!dev) {
|
|
||||||
WARN(1, "Unexpected drm device unregister!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
|
|
||||||
if (subdrv->remove)
|
|
||||||
subdrv->remove(dev, subdrv->dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
|
|
||||||
{
|
|
||||||
struct exynos_drm_subdrv *subdrv;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
|
|
||||||
if (subdrv->open) {
|
|
||||||
ret = subdrv->open(dev, subdrv->dev, file);
|
|
||||||
if (ret)
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err:
|
|
||||||
list_for_each_entry_continue_reverse(subdrv, &exynos_drm_subdrv_list, list) {
|
|
||||||
if (subdrv->close)
|
|
||||||
subdrv->close(dev, subdrv->dev, file);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
|
|
||||||
{
|
|
||||||
struct exynos_drm_subdrv *subdrv;
|
|
||||||
|
|
||||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
|
|
||||||
if (subdrv->close)
|
|
||||||
subdrv->close(dev, subdrv->dev, file);
|
|
||||||
}
|
|
||||||
}
|
|
@ -55,8 +55,7 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
file->driver_priv = file_priv;
|
file->driver_priv = file_priv;
|
||||||
|
ret = g2d_open(dev, file);
|
||||||
ret = exynos_drm_subdrv_open(dev, file);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_file_priv_free;
|
goto err_file_priv_free;
|
||||||
|
|
||||||
@ -70,7 +69,7 @@ err_file_priv_free:
|
|||||||
|
|
||||||
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
|
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
|
||||||
{
|
{
|
||||||
exynos_drm_subdrv_close(dev, file);
|
g2d_close(dev, file);
|
||||||
kfree(file->driver_priv);
|
kfree(file->driver_priv);
|
||||||
file->driver_priv = NULL;
|
file->driver_priv = NULL;
|
||||||
}
|
}
|
||||||
@ -147,13 +146,12 @@ static struct drm_driver exynos_drm_driver = {
|
|||||||
.minor = DRIVER_MINOR,
|
.minor = DRIVER_MINOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
|
||||||
static int exynos_drm_suspend(struct device *dev)
|
static int exynos_drm_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||||
struct exynos_drm_private *private;
|
struct exynos_drm_private *private;
|
||||||
|
|
||||||
if (pm_runtime_suspended(dev) || !drm_dev)
|
if (!drm_dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
private = drm_dev->dev_private;
|
private = drm_dev->dev_private;
|
||||||
@ -170,25 +168,23 @@ static int exynos_drm_suspend(struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_drm_resume(struct device *dev)
|
static void exynos_drm_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
struct drm_device *drm_dev = dev_get_drvdata(dev);
|
||||||
struct exynos_drm_private *private;
|
struct exynos_drm_private *private;
|
||||||
|
|
||||||
if (pm_runtime_suspended(dev) || !drm_dev)
|
if (!drm_dev)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
private = drm_dev->dev_private;
|
private = drm_dev->dev_private;
|
||||||
drm_atomic_helper_resume(drm_dev, private->suspend_state);
|
drm_atomic_helper_resume(drm_dev, private->suspend_state);
|
||||||
exynos_drm_fbdev_resume(drm_dev);
|
exynos_drm_fbdev_resume(drm_dev);
|
||||||
drm_kms_helper_poll_enable(drm_dev);
|
drm_kms_helper_poll_enable(drm_dev);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static const struct dev_pm_ops exynos_drm_pm_ops = {
|
static const struct dev_pm_ops exynos_drm_pm_ops = {
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_suspend, exynos_drm_resume)
|
.prepare = exynos_drm_suspend,
|
||||||
|
.complete = exynos_drm_resume,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* forward declaration */
|
/* forward declaration */
|
||||||
@ -240,6 +236,7 @@ static struct exynos_drm_driver_info exynos_drm_drivers[] = {
|
|||||||
DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE
|
DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE
|
||||||
}, {
|
}, {
|
||||||
DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D),
|
DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D),
|
||||||
|
DRM_COMPONENT_DRIVER
|
||||||
}, {
|
}, {
|
||||||
DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC),
|
DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC),
|
||||||
DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE,
|
DRM_COMPONENT_DRIVER | DRM_FIMC_DEVICE,
|
||||||
@ -376,11 +373,6 @@ static int exynos_drm_bind(struct device *dev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_unbind_all;
|
goto err_unbind_all;
|
||||||
|
|
||||||
/* Probe non kms sub drivers and virtual display driver. */
|
|
||||||
ret = exynos_drm_device_subdrv_probe(drm);
|
|
||||||
if (ret)
|
|
||||||
goto err_unbind_all;
|
|
||||||
|
|
||||||
drm_mode_config_reset(drm);
|
drm_mode_config_reset(drm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -411,7 +403,6 @@ err_cleanup_fbdev:
|
|||||||
exynos_drm_fbdev_fini(drm);
|
exynos_drm_fbdev_fini(drm);
|
||||||
err_cleanup_poll:
|
err_cleanup_poll:
|
||||||
drm_kms_helper_poll_fini(drm);
|
drm_kms_helper_poll_fini(drm);
|
||||||
exynos_drm_device_subdrv_remove(drm);
|
|
||||||
err_unbind_all:
|
err_unbind_all:
|
||||||
component_unbind_all(drm->dev, drm);
|
component_unbind_all(drm->dev, drm);
|
||||||
err_mode_config_cleanup:
|
err_mode_config_cleanup:
|
||||||
@ -420,7 +411,7 @@ err_mode_config_cleanup:
|
|||||||
err_free_private:
|
err_free_private:
|
||||||
kfree(private);
|
kfree(private);
|
||||||
err_free_drm:
|
err_free_drm:
|
||||||
drm_dev_unref(drm);
|
drm_dev_put(drm);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -431,8 +422,6 @@ static void exynos_drm_unbind(struct device *dev)
|
|||||||
|
|
||||||
drm_dev_unregister(drm);
|
drm_dev_unregister(drm);
|
||||||
|
|
||||||
exynos_drm_device_subdrv_remove(drm);
|
|
||||||
|
|
||||||
exynos_drm_fbdev_fini(drm);
|
exynos_drm_fbdev_fini(drm);
|
||||||
drm_kms_helper_poll_fini(drm);
|
drm_kms_helper_poll_fini(drm);
|
||||||
|
|
||||||
@ -444,7 +433,7 @@ static void exynos_drm_unbind(struct device *dev)
|
|||||||
drm->dev_private = NULL;
|
drm->dev_private = NULL;
|
||||||
dev_set_drvdata(dev, NULL);
|
dev_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
drm_dev_unref(drm);
|
drm_dev_put(drm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_master_ops exynos_drm_ops = {
|
static const struct component_master_ops exynos_drm_ops = {
|
||||||
|
@ -179,17 +179,13 @@ static inline void exynos_drm_pipe_clk_enable(struct exynos_drm_crtc *crtc,
|
|||||||
crtc->pipe_clk->enable(crtc->pipe_clk, enable);
|
crtc->pipe_clk->enable(crtc->pipe_clk, enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct exynos_drm_g2d_private {
|
struct drm_exynos_file_private {
|
||||||
struct device *dev;
|
/* for g2d api */
|
||||||
struct list_head inuse_cmdlist;
|
struct list_head inuse_cmdlist;
|
||||||
struct list_head event_list;
|
struct list_head event_list;
|
||||||
struct list_head userptr_list;
|
struct list_head userptr_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drm_exynos_file_private {
|
|
||||||
struct exynos_drm_g2d_private *g2d_priv;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exynos drm private structure.
|
* Exynos drm private structure.
|
||||||
*
|
*
|
||||||
@ -201,6 +197,7 @@ struct exynos_drm_private {
|
|||||||
struct drm_fb_helper *fb_helper;
|
struct drm_fb_helper *fb_helper;
|
||||||
struct drm_atomic_state *suspend_state;
|
struct drm_atomic_state *suspend_state;
|
||||||
|
|
||||||
|
struct device *g2d_dev;
|
||||||
struct device *dma_dev;
|
struct device *dma_dev;
|
||||||
void *mapping;
|
void *mapping;
|
||||||
|
|
||||||
@ -217,44 +214,6 @@ static inline struct device *to_dma_dev(struct drm_device *dev)
|
|||||||
return priv->dma_dev;
|
return priv->dma_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Exynos drm sub driver structure.
|
|
||||||
*
|
|
||||||
* @list: sub driver has its own list object to register to exynos drm driver.
|
|
||||||
* @dev: pointer to device object for subdrv device driver.
|
|
||||||
* @drm_dev: pointer to drm_device and this pointer would be set
|
|
||||||
* when sub driver calls exynos_drm_subdrv_register().
|
|
||||||
* @probe: this callback would be called by exynos drm driver after
|
|
||||||
* subdrv is registered to it.
|
|
||||||
* @remove: this callback is used to release resources created
|
|
||||||
* by probe callback.
|
|
||||||
* @open: this would be called with drm device file open.
|
|
||||||
* @close: this would be called with drm device file close.
|
|
||||||
*/
|
|
||||||
struct exynos_drm_subdrv {
|
|
||||||
struct list_head list;
|
|
||||||
struct device *dev;
|
|
||||||
struct drm_device *drm_dev;
|
|
||||||
|
|
||||||
int (*probe)(struct drm_device *drm_dev, struct device *dev);
|
|
||||||
void (*remove)(struct drm_device *drm_dev, struct device *dev);
|
|
||||||
int (*open)(struct drm_device *drm_dev, struct device *dev,
|
|
||||||
struct drm_file *file);
|
|
||||||
void (*close)(struct drm_device *drm_dev, struct device *dev,
|
|
||||||
struct drm_file *file);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* This function would be called by non kms drivers such as g2d and ipp. */
|
|
||||||
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
|
|
||||||
|
|
||||||
/* this function removes subdrv list from exynos drm driver */
|
|
||||||
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
|
|
||||||
|
|
||||||
int exynos_drm_device_subdrv_probe(struct drm_device *dev);
|
|
||||||
int exynos_drm_device_subdrv_remove(struct drm_device *dev);
|
|
||||||
int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
|
|
||||||
void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
|
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_EXYNOS_DPI
|
#ifdef CONFIG_DRM_EXYNOS_DPI
|
||||||
struct drm_encoder *exynos_dpi_probe(struct device *dev);
|
struct drm_encoder *exynos_dpi_probe(struct device *dev);
|
||||||
int exynos_dpi_remove(struct drm_encoder *encoder);
|
int exynos_dpi_remove(struct drm_encoder *encoder);
|
||||||
|
@ -1863,6 +1863,8 @@ err_clk:
|
|||||||
|
|
||||||
static const struct dev_pm_ops exynos_dsi_pm_ops = {
|
static const struct dev_pm_ops exynos_dsi_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL)
|
SET_RUNTIME_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume, NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_driver dsi_driver = {
|
struct platform_driver dsi_driver = {
|
||||||
|
@ -101,7 +101,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
|||||||
{
|
{
|
||||||
const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd);
|
const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd);
|
||||||
struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
|
struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
|
||||||
struct drm_gem_object *obj;
|
|
||||||
struct drm_framebuffer *fb;
|
struct drm_framebuffer *fb;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
@ -112,15 +111,14 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
|||||||
unsigned long size = height * mode_cmd->pitches[i] +
|
unsigned long size = height * mode_cmd->pitches[i] +
|
||||||
mode_cmd->offsets[i];
|
mode_cmd->offsets[i];
|
||||||
|
|
||||||
obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
|
exynos_gem[i] = exynos_drm_gem_get(file_priv,
|
||||||
if (!obj) {
|
mode_cmd->handles[i]);
|
||||||
|
if (!exynos_gem[i]) {
|
||||||
DRM_ERROR("failed to lookup gem object\n");
|
DRM_ERROR("failed to lookup gem object\n");
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
exynos_gem[i] = to_exynos_gem(obj);
|
|
||||||
|
|
||||||
if (size > exynos_gem[i]->size) {
|
if (size > exynos_gem[i]->size) {
|
||||||
i++;
|
i++;
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
@ -138,7 +136,7 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
while (i--)
|
while (i--)
|
||||||
drm_gem_object_unreference_unlocked(&exynos_gem[i]->base);
|
exynos_drm_gem_put(exynos_gem[i]);
|
||||||
|
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
@ -470,17 +470,18 @@ static void fimc_src_set_transf(struct fimc_context *ctx, unsigned int rotation)
|
|||||||
static void fimc_set_window(struct fimc_context *ctx,
|
static void fimc_set_window(struct fimc_context *ctx,
|
||||||
struct exynos_drm_ipp_buffer *buf)
|
struct exynos_drm_ipp_buffer *buf)
|
||||||
{
|
{
|
||||||
|
unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];
|
||||||
u32 cfg, h1, h2, v1, v2;
|
u32 cfg, h1, h2, v1, v2;
|
||||||
|
|
||||||
/* cropped image */
|
/* cropped image */
|
||||||
h1 = buf->rect.x;
|
h1 = buf->rect.x;
|
||||||
h2 = buf->buf.width - buf->rect.w - buf->rect.x;
|
h2 = real_width - buf->rect.w - buf->rect.x;
|
||||||
v1 = buf->rect.y;
|
v1 = buf->rect.y;
|
||||||
v2 = buf->buf.height - buf->rect.h - buf->rect.y;
|
v2 = buf->buf.height - buf->rect.h - buf->rect.y;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
|
DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
|
||||||
buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h,
|
buf->rect.x, buf->rect.y, buf->rect.w, buf->rect.h,
|
||||||
buf->buf.width, buf->buf.height);
|
real_width, buf->buf.height);
|
||||||
DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2);
|
DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -503,12 +504,13 @@ static void fimc_set_window(struct fimc_context *ctx,
|
|||||||
static void fimc_src_set_size(struct fimc_context *ctx,
|
static void fimc_src_set_size(struct fimc_context *ctx,
|
||||||
struct exynos_drm_ipp_buffer *buf)
|
struct exynos_drm_ipp_buffer *buf)
|
||||||
{
|
{
|
||||||
|
unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];
|
||||||
u32 cfg;
|
u32 cfg;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height);
|
DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", real_width, buf->buf.height);
|
||||||
|
|
||||||
/* original size */
|
/* original size */
|
||||||
cfg = (EXYNOS_ORGISIZE_HORIZONTAL(buf->buf.width) |
|
cfg = (EXYNOS_ORGISIZE_HORIZONTAL(real_width) |
|
||||||
EXYNOS_ORGISIZE_VERTICAL(buf->buf.height));
|
EXYNOS_ORGISIZE_VERTICAL(buf->buf.height));
|
||||||
|
|
||||||
fimc_write(ctx, cfg, EXYNOS_ORGISIZE);
|
fimc_write(ctx, cfg, EXYNOS_ORGISIZE);
|
||||||
@ -529,7 +531,7 @@ static void fimc_src_set_size(struct fimc_context *ctx,
|
|||||||
* for now, we support only ITU601 8 bit mode
|
* for now, we support only ITU601 8 bit mode
|
||||||
*/
|
*/
|
||||||
cfg = (EXYNOS_CISRCFMT_ITU601_8BIT |
|
cfg = (EXYNOS_CISRCFMT_ITU601_8BIT |
|
||||||
EXYNOS_CISRCFMT_SOURCEHSIZE(buf->buf.width) |
|
EXYNOS_CISRCFMT_SOURCEHSIZE(real_width) |
|
||||||
EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height));
|
EXYNOS_CISRCFMT_SOURCEVSIZE(buf->buf.height));
|
||||||
fimc_write(ctx, cfg, EXYNOS_CISRCFMT);
|
fimc_write(ctx, cfg, EXYNOS_CISRCFMT);
|
||||||
|
|
||||||
@ -842,12 +844,13 @@ static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc)
|
|||||||
static void fimc_dst_set_size(struct fimc_context *ctx,
|
static void fimc_dst_set_size(struct fimc_context *ctx,
|
||||||
struct exynos_drm_ipp_buffer *buf)
|
struct exynos_drm_ipp_buffer *buf)
|
||||||
{
|
{
|
||||||
|
unsigned int real_width = buf->buf.pitch[0] / buf->format->cpp[0];
|
||||||
u32 cfg, cfg_ext;
|
u32 cfg, cfg_ext;
|
||||||
|
|
||||||
DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", buf->buf.width, buf->buf.height);
|
DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", real_width, buf->buf.height);
|
||||||
|
|
||||||
/* original size */
|
/* original size */
|
||||||
cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(buf->buf.width) |
|
cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(real_width) |
|
||||||
EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height));
|
EXYNOS_ORGOSIZE_VERTICAL(buf->buf.height));
|
||||||
|
|
||||||
fimc_write(ctx, cfg, EXYNOS_ORGOSIZE);
|
fimc_write(ctx, cfg, EXYNOS_ORGOSIZE);
|
||||||
|
@ -1192,6 +1192,8 @@ static int exynos_fimd_resume(struct device *dev)
|
|||||||
|
|
||||||
static const struct dev_pm_ops exynos_fimd_pm_ops = {
|
static const struct dev_pm_ops exynos_fimd_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL)
|
SET_RUNTIME_PM_OPS(exynos_fimd_suspend, exynos_fimd_resume, NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_driver fimd_driver = {
|
struct platform_driver fimd_driver = {
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/component.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
@ -190,7 +191,7 @@ struct g2d_buf_desc {
|
|||||||
struct g2d_buf_info {
|
struct g2d_buf_info {
|
||||||
unsigned int map_nr;
|
unsigned int map_nr;
|
||||||
enum g2d_reg_type reg_types[MAX_REG_TYPE_NR];
|
enum g2d_reg_type reg_types[MAX_REG_TYPE_NR];
|
||||||
unsigned long handles[MAX_REG_TYPE_NR];
|
void *obj[MAX_REG_TYPE_NR];
|
||||||
unsigned int types[MAX_REG_TYPE_NR];
|
unsigned int types[MAX_REG_TYPE_NR];
|
||||||
struct g2d_buf_desc descs[MAX_REG_TYPE_NR];
|
struct g2d_buf_desc descs[MAX_REG_TYPE_NR];
|
||||||
};
|
};
|
||||||
@ -237,7 +238,7 @@ struct g2d_data {
|
|||||||
int irq;
|
int irq;
|
||||||
struct workqueue_struct *g2d_workq;
|
struct workqueue_struct *g2d_workq;
|
||||||
struct work_struct runqueue_work;
|
struct work_struct runqueue_work;
|
||||||
struct exynos_drm_subdrv subdrv;
|
struct drm_device *drm_dev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* cmdlist */
|
/* cmdlist */
|
||||||
@ -268,14 +269,13 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
|
|||||||
{
|
{
|
||||||
struct device *dev = g2d->dev;
|
struct device *dev = g2d->dev;
|
||||||
struct g2d_cmdlist_node *node = g2d->cmdlist_node;
|
struct g2d_cmdlist_node *node = g2d->cmdlist_node;
|
||||||
struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
|
|
||||||
int nr;
|
int nr;
|
||||||
int ret;
|
int ret;
|
||||||
struct g2d_buf_info *buf_info;
|
struct g2d_buf_info *buf_info;
|
||||||
|
|
||||||
g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE;
|
g2d->cmdlist_dma_attrs = DMA_ATTR_WRITE_COMBINE;
|
||||||
|
|
||||||
g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(subdrv->drm_dev),
|
g2d->cmdlist_pool_virt = dma_alloc_attrs(to_dma_dev(g2d->drm_dev),
|
||||||
G2D_CMDLIST_POOL_SIZE,
|
G2D_CMDLIST_POOL_SIZE,
|
||||||
&g2d->cmdlist_pool, GFP_KERNEL,
|
&g2d->cmdlist_pool, GFP_KERNEL,
|
||||||
g2d->cmdlist_dma_attrs);
|
g2d->cmdlist_dma_attrs);
|
||||||
@ -308,7 +308,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
dma_free_attrs(to_dma_dev(subdrv->drm_dev), G2D_CMDLIST_POOL_SIZE,
|
dma_free_attrs(to_dma_dev(g2d->drm_dev), G2D_CMDLIST_POOL_SIZE,
|
||||||
g2d->cmdlist_pool_virt,
|
g2d->cmdlist_pool_virt,
|
||||||
g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
|
g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
|
||||||
return ret;
|
return ret;
|
||||||
@ -316,12 +316,10 @@ err:
|
|||||||
|
|
||||||
static void g2d_fini_cmdlist(struct g2d_data *g2d)
|
static void g2d_fini_cmdlist(struct g2d_data *g2d)
|
||||||
{
|
{
|
||||||
struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
|
|
||||||
|
|
||||||
kfree(g2d->cmdlist_node);
|
kfree(g2d->cmdlist_node);
|
||||||
|
|
||||||
if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) {
|
if (g2d->cmdlist_pool_virt && g2d->cmdlist_pool) {
|
||||||
dma_free_attrs(to_dma_dev(subdrv->drm_dev),
|
dma_free_attrs(to_dma_dev(g2d->drm_dev),
|
||||||
G2D_CMDLIST_POOL_SIZE,
|
G2D_CMDLIST_POOL_SIZE,
|
||||||
g2d->cmdlist_pool_virt,
|
g2d->cmdlist_pool_virt,
|
||||||
g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
|
g2d->cmdlist_pool, g2d->cmdlist_dma_attrs);
|
||||||
@ -355,32 +353,31 @@ static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node)
|
|||||||
mutex_unlock(&g2d->cmdlist_mutex);
|
mutex_unlock(&g2d->cmdlist_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv,
|
static void g2d_add_cmdlist_to_inuse(struct drm_exynos_file_private *file_priv,
|
||||||
struct g2d_cmdlist_node *node)
|
struct g2d_cmdlist_node *node)
|
||||||
{
|
{
|
||||||
struct g2d_cmdlist_node *lnode;
|
struct g2d_cmdlist_node *lnode;
|
||||||
|
|
||||||
if (list_empty(&g2d_priv->inuse_cmdlist))
|
if (list_empty(&file_priv->inuse_cmdlist))
|
||||||
goto add_to_list;
|
goto add_to_list;
|
||||||
|
|
||||||
/* this links to base address of new cmdlist */
|
/* this links to base address of new cmdlist */
|
||||||
lnode = list_entry(g2d_priv->inuse_cmdlist.prev,
|
lnode = list_entry(file_priv->inuse_cmdlist.prev,
|
||||||
struct g2d_cmdlist_node, list);
|
struct g2d_cmdlist_node, list);
|
||||||
lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr;
|
lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr;
|
||||||
|
|
||||||
add_to_list:
|
add_to_list:
|
||||||
list_add_tail(&node->list, &g2d_priv->inuse_cmdlist);
|
list_add_tail(&node->list, &file_priv->inuse_cmdlist);
|
||||||
|
|
||||||
if (node->event)
|
if (node->event)
|
||||||
list_add_tail(&node->event->base.link, &g2d_priv->event_list);
|
list_add_tail(&node->event->base.link, &file_priv->event_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
|
static void g2d_userptr_put_dma_addr(struct g2d_data *g2d,
|
||||||
unsigned long obj,
|
void *obj,
|
||||||
bool force)
|
bool force)
|
||||||
{
|
{
|
||||||
struct g2d_cmdlist_userptr *g2d_userptr =
|
struct g2d_cmdlist_userptr *g2d_userptr = obj;
|
||||||
(struct g2d_cmdlist_userptr *)obj;
|
|
||||||
struct page **pages;
|
struct page **pages;
|
||||||
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
@ -398,7 +395,7 @@ static void g2d_userptr_put_dma_addr(struct drm_device *drm_dev,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
dma_unmap_sg(to_dma_dev(drm_dev), g2d_userptr->sgt->sgl,
|
dma_unmap_sg(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt->sgl,
|
||||||
g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL);
|
g2d_userptr->sgt->nents, DMA_BIDIRECTIONAL);
|
||||||
|
|
||||||
pages = frame_vector_pages(g2d_userptr->vec);
|
pages = frame_vector_pages(g2d_userptr->vec);
|
||||||
@ -419,16 +416,14 @@ out:
|
|||||||
kfree(g2d_userptr);
|
kfree(g2d_userptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
|
static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d,
|
||||||
unsigned long userptr,
|
unsigned long userptr,
|
||||||
unsigned long size,
|
unsigned long size,
|
||||||
struct drm_file *filp,
|
struct drm_file *filp,
|
||||||
unsigned long *obj)
|
void **obj)
|
||||||
{
|
{
|
||||||
struct drm_exynos_file_private *file_priv = filp->driver_priv;
|
struct drm_exynos_file_private *file_priv = filp->driver_priv;
|
||||||
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
|
|
||||||
struct g2d_cmdlist_userptr *g2d_userptr;
|
struct g2d_cmdlist_userptr *g2d_userptr;
|
||||||
struct g2d_data *g2d;
|
|
||||||
struct sg_table *sgt;
|
struct sg_table *sgt;
|
||||||
unsigned long start, end;
|
unsigned long start, end;
|
||||||
unsigned int npages, offset;
|
unsigned int npages, offset;
|
||||||
@ -439,10 +434,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
|
|||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
g2d = dev_get_drvdata(g2d_priv->dev);
|
|
||||||
|
|
||||||
/* check if userptr already exists in userptr_list. */
|
/* check if userptr already exists in userptr_list. */
|
||||||
list_for_each_entry(g2d_userptr, &g2d_priv->userptr_list, list) {
|
list_for_each_entry(g2d_userptr, &file_priv->userptr_list, list) {
|
||||||
if (g2d_userptr->userptr == userptr) {
|
if (g2d_userptr->userptr == userptr) {
|
||||||
/*
|
/*
|
||||||
* also check size because there could be same address
|
* also check size because there could be same address
|
||||||
@ -450,7 +443,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
|
|||||||
*/
|
*/
|
||||||
if (g2d_userptr->size == size) {
|
if (g2d_userptr->size == size) {
|
||||||
atomic_inc(&g2d_userptr->refcount);
|
atomic_inc(&g2d_userptr->refcount);
|
||||||
*obj = (unsigned long)g2d_userptr;
|
*obj = g2d_userptr;
|
||||||
|
|
||||||
return &g2d_userptr->dma_addr;
|
return &g2d_userptr->dma_addr;
|
||||||
}
|
}
|
||||||
@ -517,7 +510,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
|
|||||||
|
|
||||||
g2d_userptr->sgt = sgt;
|
g2d_userptr->sgt = sgt;
|
||||||
|
|
||||||
if (!dma_map_sg(to_dma_dev(drm_dev), sgt->sgl, sgt->nents,
|
if (!dma_map_sg(to_dma_dev(g2d->drm_dev), sgt->sgl, sgt->nents,
|
||||||
DMA_BIDIRECTIONAL)) {
|
DMA_BIDIRECTIONAL)) {
|
||||||
DRM_ERROR("failed to map sgt with dma region.\n");
|
DRM_ERROR("failed to map sgt with dma region.\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
@ -527,14 +520,14 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
|
|||||||
g2d_userptr->dma_addr = sgt->sgl[0].dma_address;
|
g2d_userptr->dma_addr = sgt->sgl[0].dma_address;
|
||||||
g2d_userptr->userptr = userptr;
|
g2d_userptr->userptr = userptr;
|
||||||
|
|
||||||
list_add_tail(&g2d_userptr->list, &g2d_priv->userptr_list);
|
list_add_tail(&g2d_userptr->list, &file_priv->userptr_list);
|
||||||
|
|
||||||
if (g2d->current_pool + (npages << PAGE_SHIFT) < g2d->max_pool) {
|
if (g2d->current_pool + (npages << PAGE_SHIFT) < g2d->max_pool) {
|
||||||
g2d->current_pool += npages << PAGE_SHIFT;
|
g2d->current_pool += npages << PAGE_SHIFT;
|
||||||
g2d_userptr->in_pool = true;
|
g2d_userptr->in_pool = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
*obj = (unsigned long)g2d_userptr;
|
*obj = g2d_userptr;
|
||||||
|
|
||||||
return &g2d_userptr->dma_addr;
|
return &g2d_userptr->dma_addr;
|
||||||
|
|
||||||
@ -556,19 +549,14 @@ err_free:
|
|||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void g2d_userptr_free_all(struct drm_device *drm_dev,
|
static void g2d_userptr_free_all(struct g2d_data *g2d, struct drm_file *filp)
|
||||||
struct g2d_data *g2d,
|
|
||||||
struct drm_file *filp)
|
|
||||||
{
|
{
|
||||||
struct drm_exynos_file_private *file_priv = filp->driver_priv;
|
struct drm_exynos_file_private *file_priv = filp->driver_priv;
|
||||||
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
|
|
||||||
struct g2d_cmdlist_userptr *g2d_userptr, *n;
|
struct g2d_cmdlist_userptr *g2d_userptr, *n;
|
||||||
|
|
||||||
list_for_each_entry_safe(g2d_userptr, n, &g2d_priv->userptr_list, list)
|
list_for_each_entry_safe(g2d_userptr, n, &file_priv->userptr_list, list)
|
||||||
if (g2d_userptr->in_pool)
|
if (g2d_userptr->in_pool)
|
||||||
g2d_userptr_put_dma_addr(drm_dev,
|
g2d_userptr_put_dma_addr(g2d, g2d_userptr, true);
|
||||||
(unsigned long)g2d_userptr,
|
|
||||||
true);
|
|
||||||
|
|
||||||
g2d->current_pool = 0;
|
g2d->current_pool = 0;
|
||||||
}
|
}
|
||||||
@ -723,26 +711,23 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|||||||
buf_desc = &buf_info->descs[reg_type];
|
buf_desc = &buf_info->descs[reg_type];
|
||||||
|
|
||||||
if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
|
if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
|
||||||
unsigned long size;
|
struct exynos_drm_gem *exynos_gem;
|
||||||
|
|
||||||
size = exynos_drm_gem_get_size(drm_dev, handle, file);
|
exynos_gem = exynos_drm_gem_get(file, handle);
|
||||||
if (!size) {
|
if (!exynos_gem) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
|
if (!g2d_check_buf_desc_is_valid(buf_desc,
|
||||||
size)) {
|
reg_type, exynos_gem->size)) {
|
||||||
|
exynos_drm_gem_put(exynos_gem);
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,
|
addr = &exynos_gem->dma_addr;
|
||||||
file);
|
buf_info->obj[reg_type] = exynos_gem;
|
||||||
if (IS_ERR(addr)) {
|
|
||||||
ret = -EFAULT;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
struct drm_exynos_g2d_userptr g2d_userptr;
|
struct drm_exynos_g2d_userptr g2d_userptr;
|
||||||
|
|
||||||
@ -758,11 +743,11 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = g2d_userptr_get_dma_addr(drm_dev,
|
addr = g2d_userptr_get_dma_addr(g2d,
|
||||||
g2d_userptr.userptr,
|
g2d_userptr.userptr,
|
||||||
g2d_userptr.size,
|
g2d_userptr.size,
|
||||||
file,
|
file,
|
||||||
&handle);
|
&buf_info->obj[reg_type]);
|
||||||
if (IS_ERR(addr)) {
|
if (IS_ERR(addr)) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto err;
|
goto err;
|
||||||
@ -771,7 +756,6 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
|
|||||||
|
|
||||||
cmdlist->data[reg_pos + 1] = *addr;
|
cmdlist->data[reg_pos + 1] = *addr;
|
||||||
buf_info->reg_types[i] = reg_type;
|
buf_info->reg_types[i] = reg_type;
|
||||||
buf_info->handles[reg_type] = handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -785,29 +769,26 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
|
|||||||
struct g2d_cmdlist_node *node,
|
struct g2d_cmdlist_node *node,
|
||||||
struct drm_file *filp)
|
struct drm_file *filp)
|
||||||
{
|
{
|
||||||
struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
|
|
||||||
struct g2d_buf_info *buf_info = &node->buf_info;
|
struct g2d_buf_info *buf_info = &node->buf_info;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < buf_info->map_nr; i++) {
|
for (i = 0; i < buf_info->map_nr; i++) {
|
||||||
struct g2d_buf_desc *buf_desc;
|
struct g2d_buf_desc *buf_desc;
|
||||||
enum g2d_reg_type reg_type;
|
enum g2d_reg_type reg_type;
|
||||||
unsigned long handle;
|
void *obj;
|
||||||
|
|
||||||
reg_type = buf_info->reg_types[i];
|
reg_type = buf_info->reg_types[i];
|
||||||
|
|
||||||
buf_desc = &buf_info->descs[reg_type];
|
buf_desc = &buf_info->descs[reg_type];
|
||||||
handle = buf_info->handles[reg_type];
|
obj = buf_info->obj[reg_type];
|
||||||
|
|
||||||
if (buf_info->types[reg_type] == BUF_TYPE_GEM)
|
if (buf_info->types[reg_type] == BUF_TYPE_GEM)
|
||||||
exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle,
|
exynos_drm_gem_put(obj);
|
||||||
filp);
|
|
||||||
else
|
else
|
||||||
g2d_userptr_put_dma_addr(subdrv->drm_dev, handle,
|
g2d_userptr_put_dma_addr(g2d, obj, false);
|
||||||
false);
|
|
||||||
|
|
||||||
buf_info->reg_types[i] = REG_TYPE_NONE;
|
buf_info->reg_types[i] = REG_TYPE_NONE;
|
||||||
buf_info->handles[reg_type] = 0;
|
buf_info->obj[reg_type] = NULL;
|
||||||
buf_info->types[reg_type] = 0;
|
buf_info->types[reg_type] = 0;
|
||||||
memset(buf_desc, 0x00, sizeof(*buf_desc));
|
memset(buf_desc, 0x00, sizeof(*buf_desc));
|
||||||
}
|
}
|
||||||
@ -922,7 +903,7 @@ static void g2d_runqueue_worker(struct work_struct *work)
|
|||||||
|
|
||||||
static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
|
static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
|
||||||
{
|
{
|
||||||
struct drm_device *drm_dev = g2d->subdrv.drm_dev;
|
struct drm_device *drm_dev = g2d->drm_dev;
|
||||||
struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;
|
struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;
|
||||||
struct drm_exynos_pending_g2d_event *e;
|
struct drm_exynos_pending_g2d_event *e;
|
||||||
struct timespec64 now;
|
struct timespec64 now;
|
||||||
@ -1031,7 +1012,7 @@ out:
|
|||||||
mutex_unlock(&g2d->runqueue_mutex);
|
mutex_unlock(&g2d->runqueue_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int g2d_check_reg_offset(struct device *dev,
|
static int g2d_check_reg_offset(struct g2d_data *g2d,
|
||||||
struct g2d_cmdlist_node *node,
|
struct g2d_cmdlist_node *node,
|
||||||
int nr, bool for_addr)
|
int nr, bool for_addr)
|
||||||
{
|
{
|
||||||
@ -1131,7 +1112,7 @@ static int g2d_check_reg_offset(struct device *dev,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
dev_err(dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]);
|
dev_err(g2d->dev, "Bad register offset: 0x%lx\n", cmdlist->data[index]);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1139,23 +1120,8 @@ err:
|
|||||||
int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data,
|
int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data,
|
||||||
struct drm_file *file)
|
struct drm_file *file)
|
||||||
{
|
{
|
||||||
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
|
||||||
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
|
|
||||||
struct device *dev;
|
|
||||||
struct g2d_data *g2d;
|
|
||||||
struct drm_exynos_g2d_get_ver *ver = data;
|
struct drm_exynos_g2d_get_ver *ver = data;
|
||||||
|
|
||||||
if (!g2d_priv)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
dev = g2d_priv->dev;
|
|
||||||
if (!dev)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
g2d = dev_get_drvdata(dev);
|
|
||||||
if (!g2d)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
ver->major = G2D_HW_MAJOR_VER;
|
ver->major = G2D_HW_MAJOR_VER;
|
||||||
ver->minor = G2D_HW_MINOR_VER;
|
ver->minor = G2D_HW_MINOR_VER;
|
||||||
|
|
||||||
@ -1166,9 +1132,8 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
struct drm_file *file)
|
struct drm_file *file)
|
||||||
{
|
{
|
||||||
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
||||||
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
struct device *dev;
|
struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev);
|
||||||
struct g2d_data *g2d;
|
|
||||||
struct drm_exynos_g2d_set_cmdlist *req = data;
|
struct drm_exynos_g2d_set_cmdlist *req = data;
|
||||||
struct drm_exynos_g2d_cmd *cmd;
|
struct drm_exynos_g2d_cmd *cmd;
|
||||||
struct drm_exynos_pending_g2d_event *e;
|
struct drm_exynos_pending_g2d_event *e;
|
||||||
@ -1177,17 +1142,6 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
int size;
|
int size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!g2d_priv)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
dev = g2d_priv->dev;
|
|
||||||
if (!dev)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
g2d = dev_get_drvdata(dev);
|
|
||||||
if (!g2d)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
node = g2d_get_cmdlist(g2d);
|
node = g2d_get_cmdlist(g2d);
|
||||||
if (!node)
|
if (!node)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -1199,7 +1153,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
*/
|
*/
|
||||||
if (req->cmd_nr > G2D_CMDLIST_DATA_NUM ||
|
if (req->cmd_nr > G2D_CMDLIST_DATA_NUM ||
|
||||||
req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) {
|
req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) {
|
||||||
dev_err(dev, "number of submitted G2D commands exceeds limit\n");
|
dev_err(g2d->dev, "number of submitted G2D commands exceeds limit\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1267,7 +1221,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
*/
|
*/
|
||||||
size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2;
|
size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2;
|
||||||
if (size > G2D_CMDLIST_DATA_NUM) {
|
if (size > G2D_CMDLIST_DATA_NUM) {
|
||||||
dev_err(dev, "cmdlist size is too big\n");
|
dev_err(g2d->dev, "cmdlist size is too big\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err_free_event;
|
goto err_free_event;
|
||||||
}
|
}
|
||||||
@ -1282,7 +1236,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
}
|
}
|
||||||
cmdlist->last += req->cmd_nr * 2;
|
cmdlist->last += req->cmd_nr * 2;
|
||||||
|
|
||||||
ret = g2d_check_reg_offset(dev, node, req->cmd_nr, false);
|
ret = g2d_check_reg_offset(g2d, node, req->cmd_nr, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_free_event;
|
goto err_free_event;
|
||||||
|
|
||||||
@ -1301,7 +1255,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
}
|
}
|
||||||
cmdlist->last += req->cmd_buf_nr * 2;
|
cmdlist->last += req->cmd_buf_nr * 2;
|
||||||
|
|
||||||
ret = g2d_check_reg_offset(dev, node, req->cmd_buf_nr, true);
|
ret = g2d_check_reg_offset(g2d, node, req->cmd_buf_nr, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_free_event;
|
goto err_free_event;
|
||||||
|
|
||||||
@ -1319,7 +1273,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
/* tail */
|
/* tail */
|
||||||
cmdlist->data[cmdlist->last] = 0;
|
cmdlist->data[cmdlist->last] = 0;
|
||||||
|
|
||||||
g2d_add_cmdlist_to_inuse(g2d_priv, node);
|
g2d_add_cmdlist_to_inuse(file_priv, node);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -1337,25 +1291,13 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
struct drm_file *file)
|
struct drm_file *file)
|
||||||
{
|
{
|
||||||
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
||||||
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
struct device *dev;
|
struct g2d_data *g2d = dev_get_drvdata(priv->g2d_dev);
|
||||||
struct g2d_data *g2d;
|
|
||||||
struct drm_exynos_g2d_exec *req = data;
|
struct drm_exynos_g2d_exec *req = data;
|
||||||
struct g2d_runqueue_node *runqueue_node;
|
struct g2d_runqueue_node *runqueue_node;
|
||||||
struct list_head *run_cmdlist;
|
struct list_head *run_cmdlist;
|
||||||
struct list_head *event_list;
|
struct list_head *event_list;
|
||||||
|
|
||||||
if (!g2d_priv)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
dev = g2d_priv->dev;
|
|
||||||
if (!dev)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
g2d = dev_get_drvdata(dev);
|
|
||||||
if (!g2d)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);
|
runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);
|
||||||
if (!runqueue_node)
|
if (!runqueue_node)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -1367,11 +1309,11 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
|
|||||||
init_completion(&runqueue_node->complete);
|
init_completion(&runqueue_node->complete);
|
||||||
runqueue_node->async = req->async;
|
runqueue_node->async = req->async;
|
||||||
|
|
||||||
list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist);
|
list_splice_init(&file_priv->inuse_cmdlist, run_cmdlist);
|
||||||
list_splice_init(&g2d_priv->event_list, event_list);
|
list_splice_init(&file_priv->event_list, event_list);
|
||||||
|
|
||||||
if (list_empty(run_cmdlist)) {
|
if (list_empty(run_cmdlist)) {
|
||||||
dev_err(dev, "there is no inuse cmdlist\n");
|
dev_err(g2d->dev, "there is no inuse cmdlist\n");
|
||||||
kmem_cache_free(g2d->runqueue_slab, runqueue_node);
|
kmem_cache_free(g2d->runqueue_slab, runqueue_node);
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
@ -1395,71 +1337,28 @@ out:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int g2d_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
|
int g2d_open(struct drm_device *drm_dev, struct drm_file *file)
|
||||||
{
|
|
||||||
struct g2d_data *g2d;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
g2d = dev_get_drvdata(dev);
|
|
||||||
if (!g2d)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
/* allocate dma-aware cmdlist buffer. */
|
|
||||||
ret = g2d_init_cmdlist(g2d);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "cmdlist init failed\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = drm_iommu_attach_device(drm_dev, dev);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "failed to enable iommu.\n");
|
|
||||||
g2d_fini_cmdlist(g2d);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void g2d_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
|
|
||||||
{
|
|
||||||
drm_iommu_detach_device(drm_dev, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int g2d_open(struct drm_device *drm_dev, struct device *dev,
|
|
||||||
struct drm_file *file)
|
|
||||||
{
|
{
|
||||||
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
||||||
struct exynos_drm_g2d_private *g2d_priv;
|
|
||||||
|
|
||||||
g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL);
|
INIT_LIST_HEAD(&file_priv->inuse_cmdlist);
|
||||||
if (!g2d_priv)
|
INIT_LIST_HEAD(&file_priv->event_list);
|
||||||
return -ENOMEM;
|
INIT_LIST_HEAD(&file_priv->userptr_list);
|
||||||
|
|
||||||
g2d_priv->dev = dev;
|
|
||||||
file_priv->g2d_priv = g2d_priv;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist);
|
|
||||||
INIT_LIST_HEAD(&g2d_priv->event_list);
|
|
||||||
INIT_LIST_HEAD(&g2d_priv->userptr_list);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void g2d_close(struct drm_device *drm_dev, struct device *dev,
|
void g2d_close(struct drm_device *drm_dev, struct drm_file *file)
|
||||||
struct drm_file *file)
|
|
||||||
{
|
{
|
||||||
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
struct drm_exynos_file_private *file_priv = file->driver_priv;
|
||||||
struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
struct g2d_data *g2d;
|
struct g2d_data *g2d;
|
||||||
struct g2d_cmdlist_node *node, *n;
|
struct g2d_cmdlist_node *node, *n;
|
||||||
|
|
||||||
if (!dev)
|
if (!priv->g2d_dev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g2d = dev_get_drvdata(dev);
|
g2d = dev_get_drvdata(priv->g2d_dev);
|
||||||
if (!g2d)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Remove the runqueue nodes that belong to us. */
|
/* Remove the runqueue nodes that belong to us. */
|
||||||
mutex_lock(&g2d->runqueue_mutex);
|
mutex_lock(&g2d->runqueue_mutex);
|
||||||
@ -1480,24 +1379,70 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev,
|
|||||||
* Properly unmap these buffers here.
|
* Properly unmap these buffers here.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&g2d->cmdlist_mutex);
|
mutex_lock(&g2d->cmdlist_mutex);
|
||||||
list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list) {
|
list_for_each_entry_safe(node, n, &file_priv->inuse_cmdlist, list) {
|
||||||
g2d_unmap_cmdlist_gem(g2d, node, file);
|
g2d_unmap_cmdlist_gem(g2d, node, file);
|
||||||
list_move_tail(&node->list, &g2d->free_cmdlist);
|
list_move_tail(&node->list, &g2d->free_cmdlist);
|
||||||
}
|
}
|
||||||
mutex_unlock(&g2d->cmdlist_mutex);
|
mutex_unlock(&g2d->cmdlist_mutex);
|
||||||
|
|
||||||
/* release all g2d_userptr in pool. */
|
/* release all g2d_userptr in pool. */
|
||||||
g2d_userptr_free_all(drm_dev, g2d, file);
|
g2d_userptr_free_all(g2d, file);
|
||||||
|
|
||||||
kfree(file_priv->g2d_priv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int g2d_bind(struct device *dev, struct device *master, void *data)
|
||||||
|
{
|
||||||
|
struct g2d_data *g2d = dev_get_drvdata(dev);
|
||||||
|
struct drm_device *drm_dev = data;
|
||||||
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
g2d->drm_dev = drm_dev;
|
||||||
|
|
||||||
|
/* allocate dma-aware cmdlist buffer. */
|
||||||
|
ret = g2d_init_cmdlist(g2d);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "cmdlist init failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = drm_iommu_attach_device(drm_dev, dev);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "failed to enable iommu.\n");
|
||||||
|
g2d_fini_cmdlist(g2d);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
priv->g2d_dev = dev;
|
||||||
|
|
||||||
|
dev_info(dev, "The Exynos G2D (ver %d.%d) successfully registered.\n",
|
||||||
|
G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void g2d_unbind(struct device *dev, struct device *master, void *data)
|
||||||
|
{
|
||||||
|
struct g2d_data *g2d = dev_get_drvdata(dev);
|
||||||
|
struct drm_device *drm_dev = data;
|
||||||
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
|
|
||||||
|
/* Suspend operation and wait for engine idle. */
|
||||||
|
set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
|
||||||
|
g2d_wait_finish(g2d, NULL);
|
||||||
|
priv->g2d_dev = NULL;
|
||||||
|
|
||||||
|
cancel_work_sync(&g2d->runqueue_work);
|
||||||
|
drm_iommu_detach_device(g2d->drm_dev, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct component_ops g2d_component_ops = {
|
||||||
|
.bind = g2d_bind,
|
||||||
|
.unbind = g2d_unbind,
|
||||||
|
};
|
||||||
|
|
||||||
static int g2d_probe(struct platform_device *pdev)
|
static int g2d_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct g2d_data *g2d;
|
struct g2d_data *g2d;
|
||||||
struct exynos_drm_subdrv *subdrv;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL);
|
g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL);
|
||||||
@ -1564,22 +1509,12 @@ static int g2d_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, g2d);
|
platform_set_drvdata(pdev, g2d);
|
||||||
|
|
||||||
subdrv = &g2d->subdrv;
|
ret = component_add(dev, &g2d_component_ops);
|
||||||
subdrv->dev = dev;
|
|
||||||
subdrv->probe = g2d_subdrv_probe;
|
|
||||||
subdrv->remove = g2d_subdrv_remove;
|
|
||||||
subdrv->open = g2d_open;
|
|
||||||
subdrv->close = g2d_close;
|
|
||||||
|
|
||||||
ret = exynos_drm_subdrv_register(subdrv);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "failed to register drm g2d device\n");
|
dev_err(dev, "failed to register drm g2d device\n");
|
||||||
goto err_put_clk;
|
goto err_put_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(dev, "The Exynos G2D (ver %d.%d) successfully probed.\n",
|
|
||||||
G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_put_clk:
|
err_put_clk:
|
||||||
@ -1595,12 +1530,7 @@ static int g2d_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct g2d_data *g2d = platform_get_drvdata(pdev);
|
struct g2d_data *g2d = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
/* Suspend operation and wait for engine idle. */
|
component_del(&pdev->dev, &g2d_component_ops);
|
||||||
set_bit(G2D_BIT_SUSPEND_RUNQUEUE, &g2d->flags);
|
|
||||||
g2d_wait_finish(g2d, NULL);
|
|
||||||
|
|
||||||
cancel_work_sync(&g2d->runqueue_work);
|
|
||||||
exynos_drm_subdrv_unregister(&g2d->subdrv);
|
|
||||||
|
|
||||||
/* There should be no locking needed here. */
|
/* There should be no locking needed here. */
|
||||||
g2d_remove_runqueue_nodes(g2d, NULL);
|
g2d_remove_runqueue_nodes(g2d, NULL);
|
||||||
|
@ -14,6 +14,9 @@ extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data,
|
|||||||
struct drm_file *file_priv);
|
struct drm_file *file_priv);
|
||||||
extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
|
extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv);
|
struct drm_file *file_priv);
|
||||||
|
|
||||||
|
extern int g2d_open(struct drm_device *drm_dev, struct drm_file *file);
|
||||||
|
extern void g2d_close(struct drm_device *drm_dev, struct drm_file *file);
|
||||||
#else
|
#else
|
||||||
static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
|
static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
@ -33,4 +36,12 @@ static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
|
|||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int g2d_open(struct drm_device *drm_dev, struct drm_file *file)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void g2d_close(struct drm_device *drm_dev, struct drm_file *file)
|
||||||
|
{ }
|
||||||
#endif
|
#endif
|
||||||
|
@ -143,7 +143,7 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
|
|||||||
DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
|
DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
|
||||||
|
|
||||||
/* drop reference from allocate - handle holds it now. */
|
/* drop reference from allocate - handle holds it now. */
|
||||||
drm_gem_object_unreference_unlocked(obj);
|
drm_gem_object_put_unlocked(obj);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -171,26 +171,6 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem *exynos_gem)
|
|||||||
kfree(exynos_gem);
|
kfree(exynos_gem);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
|
|
||||||
unsigned int gem_handle,
|
|
||||||
struct drm_file *file_priv)
|
|
||||||
{
|
|
||||||
struct exynos_drm_gem *exynos_gem;
|
|
||||||
struct drm_gem_object *obj;
|
|
||||||
|
|
||||||
obj = drm_gem_object_lookup(file_priv, gem_handle);
|
|
||||||
if (!obj) {
|
|
||||||
DRM_ERROR("failed to lookup gem object.\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
exynos_gem = to_exynos_gem(obj);
|
|
||||||
|
|
||||||
drm_gem_object_unreference_unlocked(obj);
|
|
||||||
|
|
||||||
return exynos_gem->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
|
static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
|
||||||
unsigned long size)
|
unsigned long size)
|
||||||
{
|
{
|
||||||
@ -299,43 +279,15 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data,
|
|||||||
&args->offset);
|
&args->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
|
struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp,
|
||||||
unsigned int gem_handle,
|
unsigned int gem_handle)
|
||||||
struct drm_file *filp)
|
|
||||||
{
|
|
||||||
struct exynos_drm_gem *exynos_gem;
|
|
||||||
struct drm_gem_object *obj;
|
|
||||||
|
|
||||||
obj = drm_gem_object_lookup(filp, gem_handle);
|
|
||||||
if (!obj) {
|
|
||||||
DRM_ERROR("failed to lookup gem object.\n");
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
exynos_gem = to_exynos_gem(obj);
|
|
||||||
|
|
||||||
return &exynos_gem->dma_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
|
|
||||||
unsigned int gem_handle,
|
|
||||||
struct drm_file *filp)
|
|
||||||
{
|
{
|
||||||
struct drm_gem_object *obj;
|
struct drm_gem_object *obj;
|
||||||
|
|
||||||
obj = drm_gem_object_lookup(filp, gem_handle);
|
obj = drm_gem_object_lookup(filp, gem_handle);
|
||||||
if (!obj) {
|
if (!obj)
|
||||||
DRM_ERROR("failed to lookup gem object.\n");
|
return NULL;
|
||||||
return;
|
return to_exynos_gem(obj);
|
||||||
}
|
|
||||||
|
|
||||||
drm_gem_object_unreference_unlocked(obj);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* decrease obj->refcount one more time because we has already
|
|
||||||
* increased it at exynos_drm_gem_get_dma_addr().
|
|
||||||
*/
|
|
||||||
drm_gem_object_unreference_unlocked(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
|
static int exynos_drm_gem_mmap_buffer(struct exynos_drm_gem *exynos_gem,
|
||||||
@ -383,7 +335,7 @@ int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
|
|||||||
args->flags = exynos_gem->flags;
|
args->flags = exynos_gem->flags;
|
||||||
args->size = exynos_gem->size;
|
args->size = exynos_gem->size;
|
||||||
|
|
||||||
drm_gem_object_unreference_unlocked(obj);
|
drm_gem_object_put_unlocked(obj);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -77,32 +77,26 @@ int exynos_drm_gem_map_ioctl(struct drm_device *dev, void *data,
|
|||||||
struct drm_file *file_priv);
|
struct drm_file *file_priv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get dma address from gem handle and this function could be used for
|
* get exynos drm object from gem handle, this function could be used for
|
||||||
* other drivers such as 2d/3d acceleration drivers.
|
* other drivers such as 2d/3d acceleration drivers.
|
||||||
* with this function call, gem object reference count would be increased.
|
* with this function call, gem object reference count would be increased.
|
||||||
*/
|
*/
|
||||||
dma_addr_t *exynos_drm_gem_get_dma_addr(struct drm_device *dev,
|
struct exynos_drm_gem *exynos_drm_gem_get(struct drm_file *filp,
|
||||||
unsigned int gem_handle,
|
unsigned int gem_handle);
|
||||||
struct drm_file *filp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* put dma address from gem handle and this function could be used for
|
* put exynos drm object acquired from exynos_drm_gem_get(),
|
||||||
* other drivers such as 2d/3d acceleration drivers.
|
* gem object reference count would be decreased.
|
||||||
* with this function call, gem object reference count would be decreased.
|
|
||||||
*/
|
*/
|
||||||
void exynos_drm_gem_put_dma_addr(struct drm_device *dev,
|
static inline void exynos_drm_gem_put(struct exynos_drm_gem *exynos_gem)
|
||||||
unsigned int gem_handle,
|
{
|
||||||
struct drm_file *filp);
|
drm_gem_object_put_unlocked(&exynos_gem->base);
|
||||||
|
}
|
||||||
|
|
||||||
/* get buffer information to memory region allocated by gem. */
|
/* get buffer information to memory region allocated by gem. */
|
||||||
int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
|
int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv);
|
struct drm_file *file_priv);
|
||||||
|
|
||||||
/* get buffer size to gem handle. */
|
|
||||||
unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
|
|
||||||
unsigned int gem_handle,
|
|
||||||
struct drm_file *file_priv);
|
|
||||||
|
|
||||||
/* free gem object. */
|
/* free gem object. */
|
||||||
void exynos_drm_gem_free_object(struct drm_gem_object *obj);
|
void exynos_drm_gem_free_object(struct drm_gem_object *obj);
|
||||||
|
|
||||||
|
@ -492,21 +492,25 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)
|
|||||||
GSC_IN_CHROMA_ORDER_CRCB);
|
GSC_IN_CHROMA_ORDER_CRCB);
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_NV21:
|
case DRM_FORMAT_NV21:
|
||||||
|
cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P);
|
||||||
|
break;
|
||||||
case DRM_FORMAT_NV61:
|
case DRM_FORMAT_NV61:
|
||||||
cfg |= (GSC_IN_CHROMA_ORDER_CRCB |
|
cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P);
|
||||||
GSC_IN_YUV420_2P);
|
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_YUV422:
|
case DRM_FORMAT_YUV422:
|
||||||
cfg |= GSC_IN_YUV422_3P;
|
cfg |= GSC_IN_YUV422_3P;
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_YUV420:
|
case DRM_FORMAT_YUV420:
|
||||||
|
cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P);
|
||||||
|
break;
|
||||||
case DRM_FORMAT_YVU420:
|
case DRM_FORMAT_YVU420:
|
||||||
cfg |= GSC_IN_YUV420_3P;
|
cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P);
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_NV12:
|
case DRM_FORMAT_NV12:
|
||||||
|
cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P);
|
||||||
|
break;
|
||||||
case DRM_FORMAT_NV16:
|
case DRM_FORMAT_NV16:
|
||||||
cfg |= (GSC_IN_CHROMA_ORDER_CBCR |
|
cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P);
|
||||||
GSC_IN_YUV420_2P);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,30 +527,30 @@ static void gsc_src_set_transf(struct gsc_context *ctx, unsigned int rotation)
|
|||||||
|
|
||||||
switch (degree) {
|
switch (degree) {
|
||||||
case DRM_MODE_ROTATE_0:
|
case DRM_MODE_ROTATE_0:
|
||||||
if (rotation & DRM_MODE_REFLECT_Y)
|
|
||||||
cfg |= GSC_IN_ROT_XFLIP;
|
|
||||||
if (rotation & DRM_MODE_REFLECT_X)
|
if (rotation & DRM_MODE_REFLECT_X)
|
||||||
|
cfg |= GSC_IN_ROT_XFLIP;
|
||||||
|
if (rotation & DRM_MODE_REFLECT_Y)
|
||||||
cfg |= GSC_IN_ROT_YFLIP;
|
cfg |= GSC_IN_ROT_YFLIP;
|
||||||
break;
|
break;
|
||||||
case DRM_MODE_ROTATE_90:
|
case DRM_MODE_ROTATE_90:
|
||||||
cfg |= GSC_IN_ROT_90;
|
cfg |= GSC_IN_ROT_90;
|
||||||
if (rotation & DRM_MODE_REFLECT_Y)
|
|
||||||
cfg |= GSC_IN_ROT_XFLIP;
|
|
||||||
if (rotation & DRM_MODE_REFLECT_X)
|
if (rotation & DRM_MODE_REFLECT_X)
|
||||||
|
cfg |= GSC_IN_ROT_XFLIP;
|
||||||
|
if (rotation & DRM_MODE_REFLECT_Y)
|
||||||
cfg |= GSC_IN_ROT_YFLIP;
|
cfg |= GSC_IN_ROT_YFLIP;
|
||||||
break;
|
break;
|
||||||
case DRM_MODE_ROTATE_180:
|
case DRM_MODE_ROTATE_180:
|
||||||
cfg |= GSC_IN_ROT_180;
|
cfg |= GSC_IN_ROT_180;
|
||||||
if (rotation & DRM_MODE_REFLECT_Y)
|
|
||||||
cfg &= ~GSC_IN_ROT_XFLIP;
|
|
||||||
if (rotation & DRM_MODE_REFLECT_X)
|
if (rotation & DRM_MODE_REFLECT_X)
|
||||||
|
cfg &= ~GSC_IN_ROT_XFLIP;
|
||||||
|
if (rotation & DRM_MODE_REFLECT_Y)
|
||||||
cfg &= ~GSC_IN_ROT_YFLIP;
|
cfg &= ~GSC_IN_ROT_YFLIP;
|
||||||
break;
|
break;
|
||||||
case DRM_MODE_ROTATE_270:
|
case DRM_MODE_ROTATE_270:
|
||||||
cfg |= GSC_IN_ROT_270;
|
cfg |= GSC_IN_ROT_270;
|
||||||
if (rotation & DRM_MODE_REFLECT_Y)
|
|
||||||
cfg &= ~GSC_IN_ROT_XFLIP;
|
|
||||||
if (rotation & DRM_MODE_REFLECT_X)
|
if (rotation & DRM_MODE_REFLECT_X)
|
||||||
|
cfg &= ~GSC_IN_ROT_XFLIP;
|
||||||
|
if (rotation & DRM_MODE_REFLECT_Y)
|
||||||
cfg &= ~GSC_IN_ROT_YFLIP;
|
cfg &= ~GSC_IN_ROT_YFLIP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -577,7 +581,7 @@ static void gsc_src_set_size(struct gsc_context *ctx,
|
|||||||
cfg &= ~(GSC_SRCIMG_HEIGHT_MASK |
|
cfg &= ~(GSC_SRCIMG_HEIGHT_MASK |
|
||||||
GSC_SRCIMG_WIDTH_MASK);
|
GSC_SRCIMG_WIDTH_MASK);
|
||||||
|
|
||||||
cfg |= (GSC_SRCIMG_WIDTH(buf->buf.width) |
|
cfg |= (GSC_SRCIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) |
|
||||||
GSC_SRCIMG_HEIGHT(buf->buf.height));
|
GSC_SRCIMG_HEIGHT(buf->buf.height));
|
||||||
|
|
||||||
gsc_write(cfg, GSC_SRCIMG_SIZE);
|
gsc_write(cfg, GSC_SRCIMG_SIZE);
|
||||||
@ -672,18 +676,25 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)
|
|||||||
GSC_OUT_CHROMA_ORDER_CRCB);
|
GSC_OUT_CHROMA_ORDER_CRCB);
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_NV21:
|
case DRM_FORMAT_NV21:
|
||||||
case DRM_FORMAT_NV61:
|
|
||||||
cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P);
|
cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P);
|
||||||
break;
|
break;
|
||||||
|
case DRM_FORMAT_NV61:
|
||||||
|
cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P);
|
||||||
|
break;
|
||||||
case DRM_FORMAT_YUV422:
|
case DRM_FORMAT_YUV422:
|
||||||
|
cfg |= GSC_OUT_YUV422_3P;
|
||||||
|
break;
|
||||||
case DRM_FORMAT_YUV420:
|
case DRM_FORMAT_YUV420:
|
||||||
|
cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P);
|
||||||
|
break;
|
||||||
case DRM_FORMAT_YVU420:
|
case DRM_FORMAT_YVU420:
|
||||||
cfg |= GSC_OUT_YUV420_3P;
|
cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P);
|
||||||
break;
|
break;
|
||||||
case DRM_FORMAT_NV12:
|
case DRM_FORMAT_NV12:
|
||||||
|
cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P);
|
||||||
|
break;
|
||||||
case DRM_FORMAT_NV16:
|
case DRM_FORMAT_NV16:
|
||||||
cfg |= (GSC_OUT_CHROMA_ORDER_CBCR |
|
cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P);
|
||||||
GSC_OUT_YUV420_2P);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,7 +879,7 @@ static void gsc_dst_set_size(struct gsc_context *ctx,
|
|||||||
/* original size */
|
/* original size */
|
||||||
cfg = gsc_read(GSC_DSTIMG_SIZE);
|
cfg = gsc_read(GSC_DSTIMG_SIZE);
|
||||||
cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK);
|
cfg &= ~(GSC_DSTIMG_HEIGHT_MASK | GSC_DSTIMG_WIDTH_MASK);
|
||||||
cfg |= GSC_DSTIMG_WIDTH(buf->buf.width) |
|
cfg |= GSC_DSTIMG_WIDTH(buf->buf.pitch[0] / buf->format->cpp[0]) |
|
||||||
GSC_DSTIMG_HEIGHT(buf->buf.height);
|
GSC_DSTIMG_HEIGHT(buf->buf.height);
|
||||||
gsc_write(cfg, GSC_DSTIMG_SIZE);
|
gsc_write(cfg, GSC_DSTIMG_SIZE);
|
||||||
|
|
||||||
@ -1341,7 +1352,7 @@ static const struct drm_exynos_ipp_limit gsc_5420_limits[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct drm_exynos_ipp_limit gsc_5433_limits[] = {
|
static const struct drm_exynos_ipp_limit gsc_5433_limits[] = {
|
||||||
{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 2 }, .v = { 16, 8191, 2 }) },
|
{ IPP_SIZE_LIMIT(BUFFER, .h = { 32, 8191, 16 }, .v = { 16, 8191, 2 }) },
|
||||||
{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) },
|
{ IPP_SIZE_LIMIT(AREA, .h = { 16, 4800, 1 }, .v = { 8, 3344, 1 }) },
|
||||||
{ IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) },
|
{ IPP_SIZE_LIMIT(ROTATED, .h = { 32, 2047 }, .v = { 8, 8191 }) },
|
||||||
{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
|
{ IPP_SCALE_LIMIT(.h = { (1 << 16) / 16, (1 << 16) * 8 },
|
||||||
|
@ -345,39 +345,18 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf,
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* basic checks */
|
|
||||||
if (buf->buf.width == 0 || buf->buf.height == 0)
|
|
||||||
return -EINVAL;
|
|
||||||
buf->format = drm_format_info(buf->buf.fourcc);
|
|
||||||
for (i = 0; i < buf->format->num_planes; i++) {
|
|
||||||
unsigned int width = (i == 0) ? buf->buf.width :
|
|
||||||
DIV_ROUND_UP(buf->buf.width, buf->format->hsub);
|
|
||||||
|
|
||||||
if (buf->buf.pitch[i] == 0)
|
|
||||||
buf->buf.pitch[i] = width * buf->format->cpp[i];
|
|
||||||
if (buf->buf.pitch[i] < width * buf->format->cpp[i])
|
|
||||||
return -EINVAL;
|
|
||||||
if (!buf->buf.gem_id[i])
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* pitch for additional planes must match */
|
|
||||||
if (buf->format->num_planes > 2 &&
|
|
||||||
buf->buf.pitch[1] != buf->buf.pitch[2])
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* get GEM buffers and check their size */
|
/* get GEM buffers and check their size */
|
||||||
for (i = 0; i < buf->format->num_planes; i++) {
|
for (i = 0; i < buf->format->num_planes; i++) {
|
||||||
unsigned int height = (i == 0) ? buf->buf.height :
|
unsigned int height = (i == 0) ? buf->buf.height :
|
||||||
DIV_ROUND_UP(buf->buf.height, buf->format->vsub);
|
DIV_ROUND_UP(buf->buf.height, buf->format->vsub);
|
||||||
unsigned long size = height * buf->buf.pitch[i];
|
unsigned long size = height * buf->buf.pitch[i];
|
||||||
struct drm_gem_object *obj = drm_gem_object_lookup(filp,
|
struct exynos_drm_gem *gem = exynos_drm_gem_get(filp,
|
||||||
buf->buf.gem_id[i]);
|
buf->buf.gem_id[i]);
|
||||||
if (!obj) {
|
if (!gem) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto gem_free;
|
goto gem_free;
|
||||||
}
|
}
|
||||||
buf->exynos_gem[i] = to_exynos_gem(obj);
|
buf->exynos_gem[i] = gem;
|
||||||
|
|
||||||
if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) {
|
if (size + buf->buf.offset[i] > buf->exynos_gem[i]->size) {
|
||||||
i++;
|
i++;
|
||||||
@ -391,7 +370,7 @@ static int exynos_drm_ipp_task_setup_buffer(struct exynos_drm_ipp_buffer *buf,
|
|||||||
return 0;
|
return 0;
|
||||||
gem_free:
|
gem_free:
|
||||||
while (i--) {
|
while (i--) {
|
||||||
drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base);
|
exynos_drm_gem_put(buf->exynos_gem[i]);
|
||||||
buf->exynos_gem[i] = NULL;
|
buf->exynos_gem[i] = NULL;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -404,7 +383,7 @@ static void exynos_drm_ipp_task_release_buf(struct exynos_drm_ipp_buffer *buf)
|
|||||||
if (!buf->exynos_gem[0])
|
if (!buf->exynos_gem[0])
|
||||||
return;
|
return;
|
||||||
for (i = 0; i < buf->format->num_planes; i++)
|
for (i = 0; i < buf->format->num_planes; i++)
|
||||||
drm_gem_object_put_unlocked(&buf->exynos_gem[i]->base);
|
exynos_drm_gem_put(buf->exynos_gem[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp,
|
static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp,
|
||||||
@ -428,7 +407,7 @@ enum drm_ipp_size_id {
|
|||||||
IPP_LIMIT_BUFFER, IPP_LIMIT_AREA, IPP_LIMIT_ROTATED, IPP_LIMIT_MAX
|
IPP_LIMIT_BUFFER, IPP_LIMIT_AREA, IPP_LIMIT_ROTATED, IPP_LIMIT_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
static const enum drm_ipp_size_id limit_id_fallback[IPP_LIMIT_MAX][4] = {
|
static const enum drm_exynos_ipp_limit_type limit_id_fallback[IPP_LIMIT_MAX][4] = {
|
||||||
[IPP_LIMIT_BUFFER] = { DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },
|
[IPP_LIMIT_BUFFER] = { DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },
|
||||||
[IPP_LIMIT_AREA] = { DRM_EXYNOS_IPP_LIMIT_SIZE_AREA,
|
[IPP_LIMIT_AREA] = { DRM_EXYNOS_IPP_LIMIT_SIZE_AREA,
|
||||||
DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },
|
DRM_EXYNOS_IPP_LIMIT_SIZE_BUFFER },
|
||||||
@ -495,12 +474,13 @@ static int exynos_drm_ipp_check_size_limits(struct exynos_drm_ipp_buffer *buf,
|
|||||||
enum drm_ipp_size_id id = rotate ? IPP_LIMIT_ROTATED : IPP_LIMIT_AREA;
|
enum drm_ipp_size_id id = rotate ? IPP_LIMIT_ROTATED : IPP_LIMIT_AREA;
|
||||||
struct drm_ipp_limit l;
|
struct drm_ipp_limit l;
|
||||||
struct drm_exynos_ipp_limit_val *lh = &l.h, *lv = &l.v;
|
struct drm_exynos_ipp_limit_val *lh = &l.h, *lv = &l.v;
|
||||||
|
int real_width = buf->buf.pitch[0] / buf->format->cpp[0];
|
||||||
|
|
||||||
if (!limits)
|
if (!limits)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
__get_size_limit(limits, num_limits, IPP_LIMIT_BUFFER, &l);
|
__get_size_limit(limits, num_limits, IPP_LIMIT_BUFFER, &l);
|
||||||
if (!__size_limit_check(buf->buf.width, &l.h) ||
|
if (!__size_limit_check(real_width, &l.h) ||
|
||||||
!__size_limit_check(buf->buf.height, &l.v))
|
!__size_limit_check(buf->buf.height, &l.v))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -560,10 +540,62 @@ static int exynos_drm_ipp_check_scale_limits(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int exynos_drm_ipp_check_format(struct exynos_drm_ipp_task *task,
|
||||||
|
struct exynos_drm_ipp_buffer *buf,
|
||||||
|
struct exynos_drm_ipp_buffer *src,
|
||||||
|
struct exynos_drm_ipp_buffer *dst,
|
||||||
|
bool rotate, bool swap)
|
||||||
|
{
|
||||||
|
const struct exynos_drm_ipp_formats *fmt;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
fmt = __ipp_format_get(task->ipp, buf->buf.fourcc, buf->buf.modifier,
|
||||||
|
buf == src ? DRM_EXYNOS_IPP_FORMAT_SOURCE :
|
||||||
|
DRM_EXYNOS_IPP_FORMAT_DESTINATION);
|
||||||
|
if (!fmt) {
|
||||||
|
DRM_DEBUG_DRIVER("Task %pK: %s format not supported\n", task,
|
||||||
|
buf == src ? "src" : "dst");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* basic checks */
|
||||||
|
if (buf->buf.width == 0 || buf->buf.height == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
buf->format = drm_format_info(buf->buf.fourcc);
|
||||||
|
for (i = 0; i < buf->format->num_planes; i++) {
|
||||||
|
unsigned int width = (i == 0) ? buf->buf.width :
|
||||||
|
DIV_ROUND_UP(buf->buf.width, buf->format->hsub);
|
||||||
|
|
||||||
|
if (buf->buf.pitch[i] == 0)
|
||||||
|
buf->buf.pitch[i] = width * buf->format->cpp[i];
|
||||||
|
if (buf->buf.pitch[i] < width * buf->format->cpp[i])
|
||||||
|
return -EINVAL;
|
||||||
|
if (!buf->buf.gem_id[i])
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pitch for additional planes must match */
|
||||||
|
if (buf->format->num_planes > 2 &&
|
||||||
|
buf->buf.pitch[1] != buf->buf.pitch[2])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* check driver limits */
|
||||||
|
ret = exynos_drm_ipp_check_size_limits(buf, fmt->limits,
|
||||||
|
fmt->num_limits,
|
||||||
|
rotate,
|
||||||
|
buf == dst ? swap : false);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
|
||||||
|
fmt->limits,
|
||||||
|
fmt->num_limits, swap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
|
static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
|
||||||
{
|
{
|
||||||
struct exynos_drm_ipp *ipp = task->ipp;
|
struct exynos_drm_ipp *ipp = task->ipp;
|
||||||
const struct exynos_drm_ipp_formats *src_fmt, *dst_fmt;
|
|
||||||
struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;
|
struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;
|
||||||
unsigned int rotation = task->transform.rotation;
|
unsigned int rotation = task->transform.rotation;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -607,37 +639,11 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
src_fmt = __ipp_format_get(ipp, src->buf.fourcc, src->buf.modifier,
|
ret = exynos_drm_ipp_check_format(task, src, src, dst, rotate, swap);
|
||||||
DRM_EXYNOS_IPP_FORMAT_SOURCE);
|
|
||||||
if (!src_fmt) {
|
|
||||||
DRM_DEBUG_DRIVER("Task %pK: src format not supported\n", task);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
ret = exynos_drm_ipp_check_size_limits(src, src_fmt->limits,
|
|
||||||
src_fmt->num_limits,
|
|
||||||
rotate, false);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
|
|
||||||
src_fmt->limits,
|
|
||||||
src_fmt->num_limits, swap);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
dst_fmt = __ipp_format_get(ipp, dst->buf.fourcc, dst->buf.modifier,
|
ret = exynos_drm_ipp_check_format(task, dst, src, dst, false, swap);
|
||||||
DRM_EXYNOS_IPP_FORMAT_DESTINATION);
|
|
||||||
if (!dst_fmt) {
|
|
||||||
DRM_DEBUG_DRIVER("Task %pK: dst format not supported\n", task);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
ret = exynos_drm_ipp_check_size_limits(dst, dst_fmt->limits,
|
|
||||||
dst_fmt->num_limits,
|
|
||||||
false, swap);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
ret = exynos_drm_ipp_check_scale_limits(&src->rect, &dst->rect,
|
|
||||||
dst_fmt->limits,
|
|
||||||
dst_fmt->num_limits, swap);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -367,6 +367,8 @@ static int exynos_mic_resume(struct device *dev)
|
|||||||
|
|
||||||
static const struct dev_pm_ops exynos_mic_pm_ops = {
|
static const struct dev_pm_ops exynos_mic_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
|
SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int exynos_mic_probe(struct platform_device *pdev)
|
static int exynos_mic_probe(struct platform_device *pdev)
|
||||||
|
@ -132,7 +132,7 @@ static void exynos_drm_plane_reset(struct drm_plane *plane)
|
|||||||
if (plane->state) {
|
if (plane->state) {
|
||||||
exynos_state = to_exynos_plane_state(plane->state);
|
exynos_state = to_exynos_plane_state(plane->state);
|
||||||
if (exynos_state->base.fb)
|
if (exynos_state->base.fb)
|
||||||
drm_framebuffer_unreference(exynos_state->base.fb);
|
drm_framebuffer_put(exynos_state->base.fb);
|
||||||
kfree(exynos_state);
|
kfree(exynos_state);
|
||||||
plane->state = NULL;
|
plane->state = NULL;
|
||||||
}
|
}
|
||||||
|
@ -168,9 +168,9 @@ static void rotator_dst_set_transf(struct rot_context *rot,
|
|||||||
val &= ~ROT_CONTROL_FLIP_MASK;
|
val &= ~ROT_CONTROL_FLIP_MASK;
|
||||||
|
|
||||||
if (rotation & DRM_MODE_REFLECT_X)
|
if (rotation & DRM_MODE_REFLECT_X)
|
||||||
val |= ROT_CONTROL_FLIP_HORIZONTAL;
|
|
||||||
if (rotation & DRM_MODE_REFLECT_Y)
|
|
||||||
val |= ROT_CONTROL_FLIP_VERTICAL;
|
val |= ROT_CONTROL_FLIP_VERTICAL;
|
||||||
|
if (rotation & DRM_MODE_REFLECT_Y)
|
||||||
|
val |= ROT_CONTROL_FLIP_HORIZONTAL;
|
||||||
|
|
||||||
val &= ~ROT_CONTROL_ROT_MASK;
|
val &= ~ROT_CONTROL_ROT_MASK;
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset))
|
#define scaler_write(cfg, offset) writel(cfg, scaler->regs + (offset))
|
||||||
#define SCALER_MAX_CLK 4
|
#define SCALER_MAX_CLK 4
|
||||||
#define SCALER_AUTOSUSPEND_DELAY 2000
|
#define SCALER_AUTOSUSPEND_DELAY 2000
|
||||||
|
#define SCALER_RESET_WAIT_RETRIES 100
|
||||||
|
|
||||||
struct scaler_data {
|
struct scaler_data {
|
||||||
const char *clk_name[SCALER_MAX_CLK];
|
const char *clk_name[SCALER_MAX_CLK];
|
||||||
@ -51,9 +52,9 @@ struct scaler_context {
|
|||||||
static u32 scaler_get_format(u32 drm_fmt)
|
static u32 scaler_get_format(u32 drm_fmt)
|
||||||
{
|
{
|
||||||
switch (drm_fmt) {
|
switch (drm_fmt) {
|
||||||
case DRM_FORMAT_NV21:
|
|
||||||
return SCALER_YUV420_2P_UV;
|
|
||||||
case DRM_FORMAT_NV12:
|
case DRM_FORMAT_NV12:
|
||||||
|
return SCALER_YUV420_2P_UV;
|
||||||
|
case DRM_FORMAT_NV21:
|
||||||
return SCALER_YUV420_2P_VU;
|
return SCALER_YUV420_2P_VU;
|
||||||
case DRM_FORMAT_YUV420:
|
case DRM_FORMAT_YUV420:
|
||||||
return SCALER_YUV420_3P;
|
return SCALER_YUV420_3P;
|
||||||
@ -63,15 +64,15 @@ static u32 scaler_get_format(u32 drm_fmt)
|
|||||||
return SCALER_YUV422_1P_UYVY;
|
return SCALER_YUV422_1P_UYVY;
|
||||||
case DRM_FORMAT_YVYU:
|
case DRM_FORMAT_YVYU:
|
||||||
return SCALER_YUV422_1P_YVYU;
|
return SCALER_YUV422_1P_YVYU;
|
||||||
case DRM_FORMAT_NV61:
|
|
||||||
return SCALER_YUV422_2P_UV;
|
|
||||||
case DRM_FORMAT_NV16:
|
case DRM_FORMAT_NV16:
|
||||||
|
return SCALER_YUV422_2P_UV;
|
||||||
|
case DRM_FORMAT_NV61:
|
||||||
return SCALER_YUV422_2P_VU;
|
return SCALER_YUV422_2P_VU;
|
||||||
case DRM_FORMAT_YUV422:
|
case DRM_FORMAT_YUV422:
|
||||||
return SCALER_YUV422_3P;
|
return SCALER_YUV422_3P;
|
||||||
case DRM_FORMAT_NV42:
|
|
||||||
return SCALER_YUV444_2P_UV;
|
|
||||||
case DRM_FORMAT_NV24:
|
case DRM_FORMAT_NV24:
|
||||||
|
return SCALER_YUV444_2P_UV;
|
||||||
|
case DRM_FORMAT_NV42:
|
||||||
return SCALER_YUV444_2P_VU;
|
return SCALER_YUV444_2P_VU;
|
||||||
case DRM_FORMAT_YUV444:
|
case DRM_FORMAT_YUV444:
|
||||||
return SCALER_YUV444_3P;
|
return SCALER_YUV444_3P;
|
||||||
@ -100,6 +101,23 @@ static u32 scaler_get_format(u32 drm_fmt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int scaler_reset(struct scaler_context *scaler)
|
||||||
|
{
|
||||||
|
int retry = SCALER_RESET_WAIT_RETRIES;
|
||||||
|
|
||||||
|
scaler_write(SCALER_CFG_SOFT_RESET, SCALER_CFG);
|
||||||
|
do {
|
||||||
|
cpu_relax();
|
||||||
|
} while (retry > 1 &&
|
||||||
|
scaler_read(SCALER_CFG) & SCALER_CFG_SOFT_RESET);
|
||||||
|
do {
|
||||||
|
cpu_relax();
|
||||||
|
scaler_write(1, SCALER_INT_EN);
|
||||||
|
} while (retry > 0 && scaler_read(SCALER_INT_EN) != 1);
|
||||||
|
|
||||||
|
return retry ? 0 : -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void scaler_enable_int(struct scaler_context *scaler)
|
static inline void scaler_enable_int(struct scaler_context *scaler)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
@ -354,9 +372,13 @@ static int scaler_commit(struct exynos_drm_ipp *ipp,
|
|||||||
u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc);
|
u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc);
|
||||||
struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect;
|
struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect;
|
||||||
|
|
||||||
scaler->task = task;
|
|
||||||
|
|
||||||
pm_runtime_get_sync(scaler->dev);
|
pm_runtime_get_sync(scaler->dev);
|
||||||
|
if (scaler_reset(scaler)) {
|
||||||
|
pm_runtime_put(scaler->dev);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
scaler->task = task;
|
||||||
|
|
||||||
scaler_set_src_fmt(scaler, src_fmt);
|
scaler_set_src_fmt(scaler, src_fmt);
|
||||||
scaler_set_src_base(scaler, &task->src);
|
scaler_set_src_base(scaler, &task->src);
|
||||||
@ -394,7 +416,11 @@ static inline void scaler_disable_int(struct scaler_context *scaler)
|
|||||||
|
|
||||||
static inline u32 scaler_get_int_status(struct scaler_context *scaler)
|
static inline u32 scaler_get_int_status(struct scaler_context *scaler)
|
||||||
{
|
{
|
||||||
return scaler_read(SCALER_INT_STATUS);
|
u32 val = scaler_read(SCALER_INT_STATUS);
|
||||||
|
|
||||||
|
scaler_write(val, SCALER_INT_STATUS);
|
||||||
|
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int scaler_task_done(u32 val)
|
static inline int scaler_task_done(u32 val)
|
||||||
|
@ -2093,6 +2093,8 @@ static int __maybe_unused exynos_hdmi_resume(struct device *dev)
|
|||||||
|
|
||||||
static const struct dev_pm_ops exynos_hdmi_pm_ops = {
|
static const struct dev_pm_ops exynos_hdmi_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
|
SET_RUNTIME_PM_OPS(exynos_hdmi_suspend, exynos_hdmi_resume, NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_driver hdmi_driver = {
|
struct platform_driver hdmi_driver = {
|
||||||
|
@ -837,8 +837,6 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
|
|||||||
struct drm_device *drm_dev)
|
struct drm_device *drm_dev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct exynos_drm_private *priv;
|
|
||||||
priv = drm_dev->dev_private;
|
|
||||||
|
|
||||||
mixer_ctx->drm_dev = drm_dev;
|
mixer_ctx->drm_dev = drm_dev;
|
||||||
|
|
||||||
@ -1271,6 +1269,8 @@ static int __maybe_unused exynos_mixer_resume(struct device *dev)
|
|||||||
|
|
||||||
static const struct dev_pm_ops exynos_mixer_pm_ops = {
|
static const struct dev_pm_ops exynos_mixer_pm_ops = {
|
||||||
SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
|
SET_RUNTIME_PM_OPS(exynos_mixer_suspend, exynos_mixer_resume, NULL)
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||||
|
pm_runtime_force_resume)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct platform_driver mixer_driver = {
|
struct platform_driver mixer_driver = {
|
||||||
|
@ -138,6 +138,7 @@
|
|||||||
#define GSC_OUT_YUV420_3P (3 << 4)
|
#define GSC_OUT_YUV420_3P (3 << 4)
|
||||||
#define GSC_OUT_YUV422_1P (4 << 4)
|
#define GSC_OUT_YUV422_1P (4 << 4)
|
||||||
#define GSC_OUT_YUV422_2P (5 << 4)
|
#define GSC_OUT_YUV422_2P (5 << 4)
|
||||||
|
#define GSC_OUT_YUV422_3P (6 << 4)
|
||||||
#define GSC_OUT_YUV444 (7 << 4)
|
#define GSC_OUT_YUV444 (7 << 4)
|
||||||
#define GSC_OUT_TILE_TYPE_MASK (1 << 2)
|
#define GSC_OUT_TILE_TYPE_MASK (1 << 2)
|
||||||
#define GSC_OUT_TILE_C_16x8 (0 << 2)
|
#define GSC_OUT_TILE_C_16x8 (0 << 2)
|
||||||
|
Reference in New Issue
Block a user