Commit daa98975 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'exynos-drm-next-for-v4.19' of...

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: default avatarDave Airlie <airlied@redhat.com>

Link: https://patchwork.freedesktop.org/patch/msgid/1532505748-10025-1-git-send-email-inki.dae@samsung.com
parents 52ea6a11 3f2b78d6
...@@ -4,7 +4,7 @@ ...@@ -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, ...@@ -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, ...@@ -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 @@ static int exynos5433_decon_resume(struct device *dev) ...@@ -673,6 +673,8 @@ static int exynos5433_decon_resume(struct device *dev)
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) ...@@ -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 @@ ...@@ -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) ...@@ -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[] = {
......
/* 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) ...@@ -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 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) ...@@ -70,7 +69,7 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
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 = { ...@@ -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) ...@@ -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[] = { ...@@ -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) ...@@ -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 @@ static int exynos_drm_bind(struct device *dev) ...@@ -411,7 +403,6 @@ static int exynos_drm_bind(struct device *dev)
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 @@ static int exynos_drm_bind(struct device *dev) ...@@ -420,7 +411,7 @@ static int exynos_drm_bind(struct device *dev)
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) ...@@ -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) ...@@ -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, ...@@ -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 { ...@@ -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) ...@@ -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 @@ static int __maybe_unused exynos_dsi_resume(struct device *dev) ...@@ -1863,6 +1863,8 @@ static int __maybe_unused exynos_dsi_resume(struct device *dev)
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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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 = {
......
This diff is collapsed.
...@@ -14,6 +14,9 @@ extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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[] = { ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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 { ...@@ -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, ...@@ -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( ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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 @@ ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 @@ ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment