- Refactoring of DMA and IOMMU code
. This patch series simplifies DMA mapping creation by avoiding looping all components to get dma device object, reduces code size by merging IOMMU and DMA code. - Enhance plane alpha and blend mode support . This patch series adds configurable plane and pixel blend mode support for Exynos5433 DECON device. - Fix color format setting of Mixer driver . This patch series fixes color format and range setting by splitting range and format. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJcB5QcAAoJEFc4NIkMQxK4SREP/RLc4pPHDYg5KsWC952BKYuQ iDCTygSkrT8hsp1k3/3xV6aN0DpaPSYUOkaLyBJ51xzNAOnxyqYvYWI9x+CXQ3ej dU/1gDqQHpbGbXr+qdKE081T9EgKkaayVucJ9pSs3W7dniZ/t6GJK8yG4XlydXxe nk3l2X/FFMT0e7PMeD06trnLHFOerp95dDC63QNyNcojTTV2lq2qYG//9MNy8x39 Mz20HwF+Rus46stYimScMFtJozxdeBxky/GneXdRTeiaJrO7wNBF1FcyZ7BmA8fr NSTyg4VKNdPm3RPSmZxHOVikScKo/m2SGhCTA+4SeAmSdUk0Xk1/xRG5PGHNHMIE MWXAvk3P8BcYCOYau8KlCR0Ist97DU3f62kAKY1IO9w3vT3tJ7ihEX8pUKWVQuyl m7RXwKz9iMUl3T6JKj3XGalN24Oe4GY5M6kCjebq6iFQ9Vic2m+tiRHajcH07tMK svZChqIv0OiBkNIBRIUiobhqLWo4vPJrO8hf5ZWB50oHF/JWgMMd9/g/4NdL0oAq xUdkAFGFrX8H+JJztnsgMAM46dVSg1hJSe01mjckk5R0mz5TWZact2QhsVhcYCXM gP8la9RL59FCIk7RLa8c+TnH544r27I/XXuqTaiuRPcWqs68CBBax7dtB025hq1d ClKw6SZDsbodjEEj9I7m =NeIE -----END PGP SIGNATURE----- Merge tag 'exynos-drm-next-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next - Refactoring of DMA and IOMMU code . This patch series simplifies DMA mapping creation by avoiding looping all components to get dma device object, reduces code size by merging IOMMU and DMA code. - Enhance plane alpha and blend mode support . This patch series adds configurable plane and pixel blend mode support for Exynos5433 DECON device. - Fix color format setting of Mixer driver . This patch series fixes color format and range setting by splitting range and format. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Inki Dae <inki.dae@samsung.com> Link: https://patchwork.freedesktop.org/patch/msgid/1544002853-11661-1-git-send-email-inki.dae@samsung.com
This commit is contained in:
commit
fb878d106b
|
@ -10,11 +10,6 @@ config DRM_EXYNOS
|
||||||
|
|
||||||
if DRM_EXYNOS
|
if DRM_EXYNOS
|
||||||
|
|
||||||
config DRM_EXYNOS_IOMMU
|
|
||||||
bool
|
|
||||||
depends on EXYNOS_IOMMU
|
|
||||||
default y
|
|
||||||
|
|
||||||
comment "CRTCs"
|
comment "CRTCs"
|
||||||
|
|
||||||
config DRM_EXYNOS_FIMD
|
config DRM_EXYNOS_FIMD
|
||||||
|
|
|
@ -4,10 +4,9 @@
|
||||||
# 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_plane.o
|
exynos_drm_gem.o exynos_drm_plane.o exynos_drm_dma.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_FIMD) += exynos_drm_fimd.o
|
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
|
||||||
exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o
|
exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON) += exynos5433_drm_decon.o
|
||||||
exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o
|
exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "exynos_drm_crtc.h"
|
#include "exynos_drm_crtc.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_plane.h"
|
#include "exynos_drm_plane.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
#include "regs-decon5433.h"
|
#include "regs-decon5433.h"
|
||||||
|
|
||||||
#define DSD_CFG_MUX 0x1004
|
#define DSD_CFG_MUX 0x1004
|
||||||
|
@ -84,6 +83,14 @@ static const enum drm_plane_type decon_win_types[WINDOWS_NR] = {
|
||||||
[CURSON_WIN] = DRM_PLANE_TYPE_CURSOR,
|
[CURSON_WIN] = DRM_PLANE_TYPE_CURSOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const unsigned int capabilities[WINDOWS_NR] = {
|
||||||
|
0,
|
||||||
|
EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
|
||||||
|
EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
|
||||||
|
EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
|
||||||
|
EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
|
||||||
|
};
|
||||||
|
|
||||||
static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask,
|
static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask,
|
||||||
u32 val)
|
u32 val)
|
||||||
{
|
{
|
||||||
|
@ -252,11 +259,76 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
|
||||||
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
|
decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void decon_win_set_bldeq(struct decon_context *ctx, unsigned int win,
|
||||||
|
unsigned int alpha, unsigned int pixel_alpha)
|
||||||
|
{
|
||||||
|
u32 mask = BLENDERQ_A_FUNC_F(0xf) | BLENDERQ_B_FUNC_F(0xf);
|
||||||
|
u32 val = 0;
|
||||||
|
|
||||||
|
switch (pixel_alpha) {
|
||||||
|
case DRM_MODE_BLEND_PIXEL_NONE:
|
||||||
|
case DRM_MODE_BLEND_COVERAGE:
|
||||||
|
val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA_A);
|
||||||
|
val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
|
||||||
|
break;
|
||||||
|
case DRM_MODE_BLEND_PREMULTI:
|
||||||
|
default:
|
||||||
|
if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
|
||||||
|
val |= BLENDERQ_A_FUNC_F(BLENDERQ_ALPHA0);
|
||||||
|
val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
|
||||||
|
} else {
|
||||||
|
val |= BLENDERQ_A_FUNC_F(BLENDERQ_ONE);
|
||||||
|
val |= BLENDERQ_B_FUNC_F(BLENDERQ_ONE_MINUS_ALPHA_A);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
decon_set_bits(ctx, DECON_BLENDERQx(win), mask, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win,
|
||||||
|
unsigned int alpha, unsigned int pixel_alpha)
|
||||||
|
{
|
||||||
|
u32 win_alpha = alpha >> 8;
|
||||||
|
u32 val = 0;
|
||||||
|
|
||||||
|
switch (pixel_alpha) {
|
||||||
|
case DRM_MODE_BLEND_PIXEL_NONE:
|
||||||
|
break;
|
||||||
|
case DRM_MODE_BLEND_COVERAGE:
|
||||||
|
case DRM_MODE_BLEND_PREMULTI:
|
||||||
|
default:
|
||||||
|
val |= WINCONx_ALPHA_SEL_F;
|
||||||
|
val |= WINCONx_BLD_PIX_F;
|
||||||
|
val |= WINCONx_ALPHA_MUL_F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_BLEND_MODE_MASK, val);
|
||||||
|
|
||||||
|
if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
|
||||||
|
val = VIDOSD_Wx_ALPHA_R_F(win_alpha) |
|
||||||
|
VIDOSD_Wx_ALPHA_G_F(win_alpha) |
|
||||||
|
VIDOSD_Wx_ALPHA_B_F(win_alpha);
|
||||||
|
decon_set_bits(ctx, DECON_VIDOSDxC(win),
|
||||||
|
VIDOSDxC_ALPHA0_RGB_MASK, val);
|
||||||
|
decon_set_bits(ctx, DECON_BLENDCON, BLEND_NEW, BLEND_NEW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
||||||
struct drm_framebuffer *fb)
|
struct drm_framebuffer *fb)
|
||||||
{
|
{
|
||||||
|
struct exynos_drm_plane plane = ctx->planes[win];
|
||||||
|
struct exynos_drm_plane_state *state =
|
||||||
|
to_exynos_plane_state(plane.base.state);
|
||||||
|
unsigned int alpha = state->base.alpha;
|
||||||
|
unsigned int pixel_alpha;
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
||||||
|
if (fb->format->has_alpha)
|
||||||
|
pixel_alpha = state->base.pixel_blend_mode;
|
||||||
|
else
|
||||||
|
pixel_alpha = DRM_MODE_BLEND_PIXEL_NONE;
|
||||||
|
|
||||||
val = readl(ctx->addr + DECON_WINCONx(win));
|
val = readl(ctx->addr + DECON_WINCONx(win));
|
||||||
val &= WINCONx_ENWIN_F;
|
val &= WINCONx_ENWIN_F;
|
||||||
|
|
||||||
|
@ -279,7 +351,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
||||||
case DRM_FORMAT_ARGB8888:
|
case DRM_FORMAT_ARGB8888:
|
||||||
default:
|
default:
|
||||||
val |= WINCONx_BPPMODE_32BPP_A8888;
|
val |= WINCONx_BPPMODE_32BPP_A8888;
|
||||||
val |= WINCONx_WSWP_F | WINCONx_BLD_PIX_F | WINCONx_ALPHA_SEL_F;
|
val |= WINCONx_WSWP_F;
|
||||||
val |= WINCONx_BURSTLEN_16WORD;
|
val |= WINCONx_BURSTLEN_16WORD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -298,8 +370,12 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
|
||||||
val &= ~WINCONx_BURSTLEN_MASK;
|
val &= ~WINCONx_BURSTLEN_MASK;
|
||||||
val |= WINCONx_BURSTLEN_8WORD;
|
val |= WINCONx_BURSTLEN_8WORD;
|
||||||
}
|
}
|
||||||
|
decon_set_bits(ctx, DECON_WINCONx(win), ~WINCONx_BLEND_MODE_MASK, val);
|
||||||
|
|
||||||
writel(val, ctx->addr + DECON_WINCONx(win));
|
if (win > 0) {
|
||||||
|
decon_win_set_bldmod(ctx, win, alpha, pixel_alpha);
|
||||||
|
decon_win_set_bldeq(ctx, win, alpha, pixel_alpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decon_shadow_protect(struct decon_context *ctx, bool protect)
|
static void decon_shadow_protect(struct decon_context *ctx, bool protect)
|
||||||
|
@ -552,6 +628,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
|
||||||
ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats);
|
ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats);
|
||||||
ctx->configs[win].zpos = win - ctx->first_win;
|
ctx->configs[win].zpos = win - ctx->first_win;
|
||||||
ctx->configs[win].type = decon_win_types[win];
|
ctx->configs[win].type = decon_win_types[win];
|
||||||
|
ctx->configs[win].capabilities = capabilities[win];
|
||||||
|
|
||||||
ret = exynos_plane_init(drm_dev, &ctx->planes[win], win,
|
ret = exynos_plane_init(drm_dev, &ctx->planes[win], win,
|
||||||
&ctx->configs[win]);
|
&ctx->configs[win]);
|
||||||
|
@ -569,7 +646,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
|
||||||
|
|
||||||
decon_clear_channels(ctx->crtc);
|
decon_clear_channels(ctx->crtc);
|
||||||
|
|
||||||
return drm_iommu_attach_device(drm_dev, dev);
|
return exynos_drm_register_dma(drm_dev, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decon_unbind(struct device *dev, struct device *master, void *data)
|
static void decon_unbind(struct device *dev, struct device *master, void *data)
|
||||||
|
@ -579,7 +656,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
|
||||||
decon_disable(ctx->crtc);
|
decon_disable(ctx->crtc);
|
||||||
|
|
||||||
/* detach this sub driver from iommu mapping if supported. */
|
/* detach this sub driver from iommu mapping if supported. */
|
||||||
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
|
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops decon_component_ops = {
|
static const struct component_ops decon_component_ops = {
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include "exynos_drm_plane.h"
|
#include "exynos_drm_plane.h"
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
#include "regs-decon7.h"
|
#include "regs-decon7.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -133,13 +132,13 @@ static int decon_ctx_initialize(struct decon_context *ctx,
|
||||||
|
|
||||||
decon_clear_channels(ctx->crtc);
|
decon_clear_channels(ctx->crtc);
|
||||||
|
|
||||||
return drm_iommu_attach_device(drm_dev, ctx->dev);
|
return exynos_drm_register_dma(drm_dev, ctx->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decon_ctx_remove(struct decon_context *ctx)
|
static void decon_ctx_remove(struct decon_context *ctx)
|
||||||
{
|
{
|
||||||
/* detach this sub driver from iommu mapping if supported. */
|
/* detach this sub driver from iommu mapping if supported. */
|
||||||
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
|
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 decon_calc_clkdiv(struct decon_context *ctx,
|
static u32 decon_calc_clkdiv(struct decon_context *ctx,
|
||||||
|
|
157
drivers/gpu/drm/exynos/exynos_drm_dma.c
Normal file
157
drivers/gpu/drm/exynos/exynos_drm_dma.c
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||||
|
// Author: Inki Dae <inki.dae@samsung.com>
|
||||||
|
// Author: Andrzej Hajda <a.hajda@samsung.com>
|
||||||
|
|
||||||
|
#include <drm/drmP.h>
|
||||||
|
#include <drm/exynos_drm.h>
|
||||||
|
#include <linux/dma-iommu.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
#include <linux/iommu.h>
|
||||||
|
|
||||||
|
#include "exynos_drm_drv.h"
|
||||||
|
|
||||||
|
#if defined(CONFIG_ARM_DMA_USE_IOMMU)
|
||||||
|
#include <asm/dma-iommu.h>
|
||||||
|
#else
|
||||||
|
#define arm_iommu_create_mapping(...) ({ NULL; })
|
||||||
|
#define arm_iommu_attach_device(...) ({ -ENODEV; })
|
||||||
|
#define arm_iommu_release_mapping(...) ({ })
|
||||||
|
#define arm_iommu_detach_device(...) ({ })
|
||||||
|
#define to_dma_iommu_mapping(dev) NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CONFIG_IOMMU_DMA)
|
||||||
|
#define iommu_dma_init_domain(...) ({ -EINVAL; })
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EXYNOS_DEV_ADDR_START 0x20000000
|
||||||
|
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
|
||||||
|
|
||||||
|
static inline int configure_dma_max_seg_size(struct device *dev)
|
||||||
|
{
|
||||||
|
if (!dev->dma_parms)
|
||||||
|
dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
|
||||||
|
if (!dev->dma_parms)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void clear_dma_max_seg_size(struct device *dev)
|
||||||
|
{
|
||||||
|
kfree(dev->dma_parms);
|
||||||
|
dev->dma_parms = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* drm_iommu_attach_device- attach device to iommu mapping
|
||||||
|
*
|
||||||
|
* @drm_dev: DRM device
|
||||||
|
* @subdrv_dev: device to be attach
|
||||||
|
*
|
||||||
|
* This function should be called by sub drivers to attach it to iommu
|
||||||
|
* mapping.
|
||||||
|
*/
|
||||||
|
static int drm_iommu_attach_device(struct drm_device *drm_dev,
|
||||||
|
struct device *subdrv_dev)
|
||||||
|
{
|
||||||
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
|
||||||
|
DRM_ERROR("Device %s lacks support for IOMMU\n",
|
||||||
|
dev_name(subdrv_dev));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = configure_dma_max_seg_size(subdrv_dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
|
||||||
|
if (to_dma_iommu_mapping(subdrv_dev))
|
||||||
|
arm_iommu_detach_device(subdrv_dev);
|
||||||
|
|
||||||
|
ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
|
||||||
|
} else if (IS_ENABLED(CONFIG_IOMMU_DMA)) {
|
||||||
|
ret = iommu_attach_device(priv->mapping, subdrv_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
clear_dma_max_seg_size(subdrv_dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* drm_iommu_detach_device -detach device address space mapping from device
|
||||||
|
*
|
||||||
|
* @drm_dev: DRM device
|
||||||
|
* @subdrv_dev: device to be detached
|
||||||
|
*
|
||||||
|
* This function should be called by sub drivers to detach it from iommu
|
||||||
|
* mapping
|
||||||
|
*/
|
||||||
|
static void drm_iommu_detach_device(struct drm_device *drm_dev,
|
||||||
|
struct device *subdrv_dev)
|
||||||
|
{
|
||||||
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
|
||||||
|
arm_iommu_detach_device(subdrv_dev);
|
||||||
|
else if (IS_ENABLED(CONFIG_IOMMU_DMA))
|
||||||
|
iommu_detach_device(priv->mapping, subdrv_dev);
|
||||||
|
|
||||||
|
clear_dma_max_seg_size(subdrv_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
|
||||||
|
{
|
||||||
|
struct exynos_drm_private *priv = drm->dev_private;
|
||||||
|
|
||||||
|
if (!priv->dma_dev) {
|
||||||
|
priv->dma_dev = dev;
|
||||||
|
DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
|
||||||
|
dev_name(dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_EXYNOS_IOMMU))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!priv->mapping) {
|
||||||
|
void *mapping;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
|
||||||
|
mapping = arm_iommu_create_mapping(&platform_bus_type,
|
||||||
|
EXYNOS_DEV_ADDR_START, EXYNOS_DEV_ADDR_SIZE);
|
||||||
|
else if (IS_ENABLED(CONFIG_IOMMU_DMA))
|
||||||
|
mapping = iommu_get_domain_for_dev(priv->dma_dev);
|
||||||
|
|
||||||
|
if (IS_ERR(mapping))
|
||||||
|
return PTR_ERR(mapping);
|
||||||
|
priv->mapping = mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drm_iommu_attach_device(drm, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev)
|
||||||
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_EXYNOS_IOMMU))
|
||||||
|
drm_iommu_detach_device(drm, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exynos_drm_cleanup_dma(struct drm_device *drm)
|
||||||
|
{
|
||||||
|
struct exynos_drm_private *priv = drm->dev_private;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_EXYNOS_IOMMU))
|
||||||
|
return;
|
||||||
|
|
||||||
|
arm_iommu_release_mapping(priv->mapping);
|
||||||
|
priv->mapping = NULL;
|
||||||
|
priv->dma_dev = NULL;
|
||||||
|
}
|
|
@ -30,7 +30,6 @@
|
||||||
#include "exynos_drm_ipp.h"
|
#include "exynos_drm_ipp.h"
|
||||||
#include "exynos_drm_vidi.h"
|
#include "exynos_drm_vidi.h"
|
||||||
#include "exynos_drm_g2d.h"
|
#include "exynos_drm_g2d.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
|
|
||||||
#define DRIVER_NAME "exynos"
|
#define DRIVER_NAME "exynos"
|
||||||
#define DRIVER_DESC "Samsung SoC DRM"
|
#define DRIVER_DESC "Samsung SoC DRM"
|
||||||
|
@ -175,8 +174,7 @@ struct exynos_drm_driver_info {
|
||||||
|
|
||||||
#define DRM_COMPONENT_DRIVER BIT(0) /* supports component framework */
|
#define DRM_COMPONENT_DRIVER BIT(0) /* supports component framework */
|
||||||
#define DRM_VIRTUAL_DEVICE BIT(1) /* create virtual platform device */
|
#define DRM_VIRTUAL_DEVICE BIT(1) /* create virtual platform device */
|
||||||
#define DRM_DMA_DEVICE BIT(2) /* can be used for dma allocations */
|
#define DRM_FIMC_DEVICE BIT(2) /* devices shared with V4L2 subsystem */
|
||||||
#define DRM_FIMC_DEVICE BIT(3) /* devices shared with V4L2 subsystem */
|
|
||||||
|
|
||||||
#define DRV_PTR(drv, cond) (IS_ENABLED(cond) ? &drv : NULL)
|
#define DRV_PTR(drv, cond) (IS_ENABLED(cond) ? &drv : NULL)
|
||||||
|
|
||||||
|
@ -187,16 +185,16 @@ struct exynos_drm_driver_info {
|
||||||
static struct exynos_drm_driver_info exynos_drm_drivers[] = {
|
static struct exynos_drm_driver_info exynos_drm_drivers[] = {
|
||||||
{
|
{
|
||||||
DRV_PTR(fimd_driver, CONFIG_DRM_EXYNOS_FIMD),
|
DRV_PTR(fimd_driver, CONFIG_DRM_EXYNOS_FIMD),
|
||||||
DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
|
DRM_COMPONENT_DRIVER
|
||||||
}, {
|
}, {
|
||||||
DRV_PTR(exynos5433_decon_driver, CONFIG_DRM_EXYNOS5433_DECON),
|
DRV_PTR(exynos5433_decon_driver, CONFIG_DRM_EXYNOS5433_DECON),
|
||||||
DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
|
DRM_COMPONENT_DRIVER
|
||||||
}, {
|
}, {
|
||||||
DRV_PTR(decon_driver, CONFIG_DRM_EXYNOS7_DECON),
|
DRV_PTR(decon_driver, CONFIG_DRM_EXYNOS7_DECON),
|
||||||
DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
|
DRM_COMPONENT_DRIVER
|
||||||
}, {
|
}, {
|
||||||
DRV_PTR(mixer_driver, CONFIG_DRM_EXYNOS_MIXER),
|
DRV_PTR(mixer_driver, CONFIG_DRM_EXYNOS_MIXER),
|
||||||
DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
|
DRM_COMPONENT_DRIVER
|
||||||
}, {
|
}, {
|
||||||
DRV_PTR(mic_driver, CONFIG_DRM_EXYNOS_MIC),
|
DRV_PTR(mic_driver, CONFIG_DRM_EXYNOS_MIC),
|
||||||
DRM_COMPONENT_DRIVER
|
DRM_COMPONENT_DRIVER
|
||||||
|
@ -267,27 +265,6 @@ static struct component_match *exynos_drm_match_add(struct device *dev)
|
||||||
return match ?: ERR_PTR(-ENODEV);
|
return match ?: ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device *exynos_drm_get_dma_device(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
|
|
||||||
struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
|
|
||||||
struct device *dev;
|
|
||||||
|
|
||||||
if (!info->driver || !(info->flags & DRM_DMA_DEVICE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
while ((dev = bus_find_device(&platform_bus_type, NULL,
|
|
||||||
&info->driver->driver,
|
|
||||||
(void *)platform_bus_type.match))) {
|
|
||||||
put_device(dev);
|
|
||||||
return dev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exynos_drm_bind(struct device *dev)
|
static int exynos_drm_bind(struct device *dev)
|
||||||
{
|
{
|
||||||
struct exynos_drm_private *private;
|
struct exynos_drm_private *private;
|
||||||
|
@ -312,23 +289,6 @@ static int exynos_drm_bind(struct device *dev)
|
||||||
dev_set_drvdata(dev, drm);
|
dev_set_drvdata(dev, drm);
|
||||||
drm->dev_private = (void *)private;
|
drm->dev_private = (void *)private;
|
||||||
|
|
||||||
/* the first real CRTC device is used for all dma mapping operations */
|
|
||||||
private->dma_dev = exynos_drm_get_dma_device();
|
|
||||||
if (!private->dma_dev) {
|
|
||||||
DRM_ERROR("no device found for DMA mapping operations.\n");
|
|
||||||
ret = -ENODEV;
|
|
||||||
goto err_free_private;
|
|
||||||
}
|
|
||||||
DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
|
|
||||||
dev_name(private->dma_dev));
|
|
||||||
|
|
||||||
/* create common IOMMU mapping for all devices attached to Exynos DRM */
|
|
||||||
ret = drm_create_iommu_mapping(drm);
|
|
||||||
if (ret < 0) {
|
|
||||||
DRM_ERROR("failed to create iommu mapping.\n");
|
|
||||||
goto err_free_private;
|
|
||||||
}
|
|
||||||
|
|
||||||
drm_mode_config_init(drm);
|
drm_mode_config_init(drm);
|
||||||
|
|
||||||
exynos_drm_mode_config_init(drm);
|
exynos_drm_mode_config_init(drm);
|
||||||
|
@ -385,8 +345,7 @@ err_unbind_all:
|
||||||
component_unbind_all(drm->dev, drm);
|
component_unbind_all(drm->dev, drm);
|
||||||
err_mode_config_cleanup:
|
err_mode_config_cleanup:
|
||||||
drm_mode_config_cleanup(drm);
|
drm_mode_config_cleanup(drm);
|
||||||
drm_release_iommu_mapping(drm);
|
exynos_drm_cleanup_dma(drm);
|
||||||
err_free_private:
|
|
||||||
kfree(private);
|
kfree(private);
|
||||||
err_free_drm:
|
err_free_drm:
|
||||||
drm_dev_put(drm);
|
drm_dev_put(drm);
|
||||||
|
@ -405,7 +364,7 @@ static void exynos_drm_unbind(struct device *dev)
|
||||||
|
|
||||||
component_unbind_all(drm->dev, drm);
|
component_unbind_all(drm->dev, drm);
|
||||||
drm_mode_config_cleanup(drm);
|
drm_mode_config_cleanup(drm);
|
||||||
drm_release_iommu_mapping(drm);
|
exynos_drm_cleanup_dma(drm);
|
||||||
|
|
||||||
kfree(drm->dev_private);
|
kfree(drm->dev_private);
|
||||||
drm->dev_private = NULL;
|
drm->dev_private = NULL;
|
||||||
|
|
|
@ -214,6 +214,17 @@ static inline struct device *to_dma_dev(struct drm_device *dev)
|
||||||
return priv->dma_dev;
|
return priv->dma_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
|
||||||
|
{
|
||||||
|
struct exynos_drm_private *priv = drm_dev->dev_private;
|
||||||
|
|
||||||
|
return priv->mapping ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exynos_drm_register_dma(struct drm_device *drm, struct device *dev);
|
||||||
|
void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev);
|
||||||
|
void exynos_drm_cleanup_dma(struct drm_device *drm);
|
||||||
|
|
||||||
#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);
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_fbdev.h"
|
#include "exynos_drm_fbdev.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
#include "exynos_drm_crtc.h"
|
#include "exynos_drm_crtc.h"
|
||||||
|
|
||||||
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
|
static int check_fb_gem_memory_type(struct drm_device *drm_dev,
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_fbdev.h"
|
#include "exynos_drm_fbdev.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
|
|
||||||
#define MAX_CONNECTOR 4
|
#define MAX_CONNECTOR 4
|
||||||
#define PREFERRED_BPP 32
|
#define PREFERRED_BPP 32
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <drm/exynos_drm.h>
|
#include <drm/exynos_drm.h>
|
||||||
#include "regs-fimc.h"
|
#include "regs-fimc.h"
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
#include "exynos_drm_ipp.h"
|
#include "exynos_drm_ipp.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1129,7 +1128,7 @@ static int fimc_bind(struct device *dev, struct device *master, void *data)
|
||||||
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
||||||
|
|
||||||
ctx->drm_dev = drm_dev;
|
ctx->drm_dev = drm_dev;
|
||||||
drm_iommu_attach_device(drm_dev, dev);
|
exynos_drm_register_dma(drm_dev, dev);
|
||||||
|
|
||||||
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
||||||
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
|
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
|
||||||
|
@ -1149,7 +1148,7 @@ static void fimc_unbind(struct device *dev, struct device *master,
|
||||||
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
||||||
|
|
||||||
exynos_drm_ipp_unregister(drm_dev, ipp);
|
exynos_drm_ipp_unregister(drm_dev, ipp);
|
||||||
drm_iommu_detach_device(drm_dev, dev);
|
exynos_drm_unregister_dma(drm_dev, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops fimc_component_ops = {
|
static const struct component_ops fimc_component_ops = {
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_crtc.h"
|
#include "exynos_drm_crtc.h"
|
||||||
#include "exynos_drm_plane.h"
|
#include "exynos_drm_plane.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIMD stands for Fully Interactive Mobile Display and
|
* FIMD stands for Fully Interactive Mobile Display and
|
||||||
|
@ -1011,7 +1010,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
|
||||||
if (is_drm_iommu_supported(drm_dev))
|
if (is_drm_iommu_supported(drm_dev))
|
||||||
fimd_clear_channels(ctx->crtc);
|
fimd_clear_channels(ctx->crtc);
|
||||||
|
|
||||||
return drm_iommu_attach_device(drm_dev, dev);
|
return exynos_drm_register_dma(drm_dev, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fimd_unbind(struct device *dev, struct device *master,
|
static void fimd_unbind(struct device *dev, struct device *master,
|
||||||
|
@ -1021,7 +1020,7 @@ static void fimd_unbind(struct device *dev, struct device *master,
|
||||||
|
|
||||||
fimd_disable(ctx->crtc);
|
fimd_disable(ctx->crtc);
|
||||||
|
|
||||||
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
|
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
|
||||||
|
|
||||||
if (ctx->encoder)
|
if (ctx->encoder)
|
||||||
exynos_dpi_remove(ctx->encoder);
|
exynos_dpi_remove(ctx->encoder);
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_g2d.h"
|
#include "exynos_drm_g2d.h"
|
||||||
#include "exynos_drm_gem.h"
|
#include "exynos_drm_gem.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
|
|
||||||
#define G2D_HW_MAJOR_VER 4
|
#define G2D_HW_MAJOR_VER 4
|
||||||
#define G2D_HW_MINOR_VER 1
|
#define G2D_HW_MINOR_VER 1
|
||||||
|
@ -1405,7 +1404,7 @@ static int g2d_bind(struct device *dev, struct device *master, void *data)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = drm_iommu_attach_device(drm_dev, dev);
|
ret = exynos_drm_register_dma(drm_dev, dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "failed to enable iommu.\n");
|
dev_err(dev, "failed to enable iommu.\n");
|
||||||
g2d_fini_cmdlist(g2d);
|
g2d_fini_cmdlist(g2d);
|
||||||
|
@ -1430,7 +1429,7 @@ static void g2d_unbind(struct device *dev, struct device *master, void *data)
|
||||||
priv->g2d_dev = NULL;
|
priv->g2d_dev = NULL;
|
||||||
|
|
||||||
cancel_work_sync(&g2d->runqueue_work);
|
cancel_work_sync(&g2d->runqueue_work);
|
||||||
drm_iommu_detach_device(g2d->drm_dev, dev);
|
exynos_drm_unregister_dma(g2d->drm_dev, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops g2d_component_ops = {
|
static const struct component_ops g2d_component_ops = {
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_gem.h"
|
#include "exynos_drm_gem.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
|
|
||||||
static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
|
static int exynos_drm_alloc_buf(struct exynos_drm_gem *exynos_gem)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include <drm/exynos_drm.h>
|
#include <drm/exynos_drm.h>
|
||||||
#include "regs-gsc.h"
|
#include "regs-gsc.h"
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
#include "exynos_drm_ipp.h"
|
#include "exynos_drm_ipp.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1170,7 +1169,7 @@ static int gsc_bind(struct device *dev, struct device *master, void *data)
|
||||||
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
||||||
|
|
||||||
ctx->drm_dev = drm_dev;
|
ctx->drm_dev = drm_dev;
|
||||||
drm_iommu_attach_device(drm_dev, dev);
|
exynos_drm_register_dma(drm_dev, dev);
|
||||||
|
|
||||||
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
||||||
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
|
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
|
||||||
|
@ -1190,7 +1189,7 @@ static void gsc_unbind(struct device *dev, struct device *master,
|
||||||
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
struct exynos_drm_ipp *ipp = &ctx->ipp;
|
||||||
|
|
||||||
exynos_drm_ipp_unregister(drm_dev, ipp);
|
exynos_drm_ipp_unregister(drm_dev, ipp);
|
||||||
drm_iommu_detach_device(drm_dev, dev);
|
exynos_drm_unregister_dma(drm_dev, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops gsc_component_ops = {
|
static const struct component_ops gsc_component_ops = {
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
/* exynos_drm_iommu.c
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
||||||
* Author: Inki Dae <inki.dae@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 <drm/exynos_drm.h>
|
|
||||||
|
|
||||||
#include <linux/dma-mapping.h>
|
|
||||||
#include <linux/iommu.h>
|
|
||||||
|
|
||||||
#include "exynos_drm_drv.h"
|
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
|
|
||||||
static inline int configure_dma_max_seg_size(struct device *dev)
|
|
||||||
{
|
|
||||||
if (!dev->dma_parms)
|
|
||||||
dev->dma_parms = kzalloc(sizeof(*dev->dma_parms), GFP_KERNEL);
|
|
||||||
if (!dev->dma_parms)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void clear_dma_max_seg_size(struct device *dev)
|
|
||||||
{
|
|
||||||
kfree(dev->dma_parms);
|
|
||||||
dev->dma_parms = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* drm_create_iommu_mapping - create a mapping structure
|
|
||||||
*
|
|
||||||
* @drm_dev: DRM device
|
|
||||||
*/
|
|
||||||
int drm_create_iommu_mapping(struct drm_device *drm_dev)
|
|
||||||
{
|
|
||||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
|
||||||
|
|
||||||
return __exynos_iommu_create_mapping(priv, EXYNOS_DEV_ADDR_START,
|
|
||||||
EXYNOS_DEV_ADDR_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* drm_release_iommu_mapping - release iommu mapping structure
|
|
||||||
*
|
|
||||||
* @drm_dev: DRM device
|
|
||||||
*/
|
|
||||||
void drm_release_iommu_mapping(struct drm_device *drm_dev)
|
|
||||||
{
|
|
||||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
|
||||||
|
|
||||||
__exynos_iommu_release_mapping(priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* drm_iommu_attach_device- attach device to iommu mapping
|
|
||||||
*
|
|
||||||
* @drm_dev: DRM device
|
|
||||||
* @subdrv_dev: device to be attach
|
|
||||||
*
|
|
||||||
* This function should be called by sub drivers to attach it to iommu
|
|
||||||
* mapping.
|
|
||||||
*/
|
|
||||||
int drm_iommu_attach_device(struct drm_device *drm_dev,
|
|
||||||
struct device *subdrv_dev)
|
|
||||||
{
|
|
||||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (get_dma_ops(priv->dma_dev) != get_dma_ops(subdrv_dev)) {
|
|
||||||
DRM_ERROR("Device %s lacks support for IOMMU\n",
|
|
||||||
dev_name(subdrv_dev));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = configure_dma_max_seg_size(subdrv_dev);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
ret = __exynos_iommu_attach(priv, subdrv_dev);
|
|
||||||
if (ret)
|
|
||||||
clear_dma_max_seg_size(subdrv_dev);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* drm_iommu_detach_device -detach device address space mapping from device
|
|
||||||
*
|
|
||||||
* @drm_dev: DRM device
|
|
||||||
* @subdrv_dev: device to be detached
|
|
||||||
*
|
|
||||||
* This function should be called by sub drivers to detach it from iommu
|
|
||||||
* mapping
|
|
||||||
*/
|
|
||||||
void drm_iommu_detach_device(struct drm_device *drm_dev,
|
|
||||||
struct device *subdrv_dev)
|
|
||||||
{
|
|
||||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
|
||||||
|
|
||||||
__exynos_iommu_detach(priv, subdrv_dev);
|
|
||||||
clear_dma_max_seg_size(subdrv_dev);
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
/* exynos_drm_iommu.h
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
||||||
* Authoer: Inki Dae <inki.dae@samsung.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the
|
|
||||||
* Free Software Foundation; either version 2 of the License, or (at your
|
|
||||||
* option) any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _EXYNOS_DRM_IOMMU_H_
|
|
||||||
#define _EXYNOS_DRM_IOMMU_H_
|
|
||||||
|
|
||||||
#define EXYNOS_DEV_ADDR_START 0x20000000
|
|
||||||
#define EXYNOS_DEV_ADDR_SIZE 0x40000000
|
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_EXYNOS_IOMMU
|
|
||||||
|
|
||||||
#if defined(CONFIG_ARM_DMA_USE_IOMMU)
|
|
||||||
#include <asm/dma-iommu.h>
|
|
||||||
|
|
||||||
static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
|
|
||||||
unsigned long start, unsigned long size)
|
|
||||||
{
|
|
||||||
priv->mapping = arm_iommu_create_mapping(&platform_bus_type, start,
|
|
||||||
size);
|
|
||||||
return IS_ERR(priv->mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
__exynos_iommu_release_mapping(struct exynos_drm_private *priv)
|
|
||||||
{
|
|
||||||
arm_iommu_release_mapping(priv->mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
|
|
||||||
struct device *dev)
|
|
||||||
{
|
|
||||||
if (dev->archdata.mapping)
|
|
||||||
arm_iommu_detach_device(dev);
|
|
||||||
|
|
||||||
return arm_iommu_attach_device(dev, priv->mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
|
|
||||||
struct device *dev)
|
|
||||||
{
|
|
||||||
arm_iommu_detach_device(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(CONFIG_IOMMU_DMA)
|
|
||||||
#include <linux/dma-iommu.h>
|
|
||||||
|
|
||||||
static inline int __exynos_iommu_create_mapping(struct exynos_drm_private *priv,
|
|
||||||
unsigned long start, unsigned long size)
|
|
||||||
{
|
|
||||||
priv->mapping = iommu_get_domain_for_dev(priv->dma_dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __exynos_iommu_release_mapping(struct exynos_drm_private *priv)
|
|
||||||
{
|
|
||||||
priv->mapping = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int __exynos_iommu_attach(struct exynos_drm_private *priv,
|
|
||||||
struct device *dev)
|
|
||||||
{
|
|
||||||
struct iommu_domain *domain = priv->mapping;
|
|
||||||
|
|
||||||
if (dev != priv->dma_dev)
|
|
||||||
return iommu_attach_device(domain, dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __exynos_iommu_detach(struct exynos_drm_private *priv,
|
|
||||||
struct device *dev)
|
|
||||||
{
|
|
||||||
struct iommu_domain *domain = priv->mapping;
|
|
||||||
|
|
||||||
if (dev != priv->dma_dev)
|
|
||||||
iommu_detach_device(domain, dev);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#error Unsupported architecture and IOMMU/DMA-mapping glue code
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int drm_create_iommu_mapping(struct drm_device *drm_dev);
|
|
||||||
|
|
||||||
void drm_release_iommu_mapping(struct drm_device *drm_dev);
|
|
||||||
|
|
||||||
int drm_iommu_attach_device(struct drm_device *drm_dev,
|
|
||||||
struct device *subdrv_dev);
|
|
||||||
|
|
||||||
void drm_iommu_detach_device(struct drm_device *dev_dev,
|
|
||||||
struct device *subdrv_dev);
|
|
||||||
|
|
||||||
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
|
|
||||||
{
|
|
||||||
struct exynos_drm_private *priv = drm_dev->dev_private;
|
|
||||||
|
|
||||||
return priv->mapping ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void drm_release_iommu_mapping(struct drm_device *drm_dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int drm_iommu_attach_device(struct drm_device *drm_dev,
|
|
||||||
struct device *subdrv_dev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void drm_iommu_detach_device(struct drm_device *drm_dev,
|
|
||||||
struct device *subdrv_dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include <drm/exynos_drm.h>
|
#include <drm/exynos_drm.h>
|
||||||
#include "regs-rotator.h"
|
#include "regs-rotator.h"
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
#include "exynos_drm_ipp.h"
|
#include "exynos_drm_ipp.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -244,7 +243,7 @@ static int rotator_bind(struct device *dev, struct device *master, void *data)
|
||||||
struct exynos_drm_ipp *ipp = &rot->ipp;
|
struct exynos_drm_ipp *ipp = &rot->ipp;
|
||||||
|
|
||||||
rot->drm_dev = drm_dev;
|
rot->drm_dev = drm_dev;
|
||||||
drm_iommu_attach_device(drm_dev, dev);
|
exynos_drm_register_dma(drm_dev, dev);
|
||||||
|
|
||||||
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
||||||
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE,
|
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE,
|
||||||
|
@ -263,7 +262,7 @@ static void rotator_unbind(struct device *dev, struct device *master,
|
||||||
struct exynos_drm_ipp *ipp = &rot->ipp;
|
struct exynos_drm_ipp *ipp = &rot->ipp;
|
||||||
|
|
||||||
exynos_drm_ipp_unregister(drm_dev, ipp);
|
exynos_drm_ipp_unregister(drm_dev, ipp);
|
||||||
drm_iommu_detach_device(rot->drm_dev, rot->dev);
|
exynos_drm_unregister_dma(rot->drm_dev, rot->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops rotator_component_ops = {
|
static const struct component_ops rotator_component_ops = {
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include "regs-scaler.h"
|
#include "regs-scaler.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_drv.h"
|
#include "exynos_drm_drv.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
#include "exynos_drm_ipp.h"
|
#include "exynos_drm_ipp.h"
|
||||||
|
|
||||||
#define scaler_read(offset) readl(scaler->regs + (offset))
|
#define scaler_read(offset) readl(scaler->regs + (offset))
|
||||||
|
@ -452,7 +451,7 @@ static int scaler_bind(struct device *dev, struct device *master, void *data)
|
||||||
struct exynos_drm_ipp *ipp = &scaler->ipp;
|
struct exynos_drm_ipp *ipp = &scaler->ipp;
|
||||||
|
|
||||||
scaler->drm_dev = drm_dev;
|
scaler->drm_dev = drm_dev;
|
||||||
drm_iommu_attach_device(drm_dev, dev);
|
exynos_drm_register_dma(drm_dev, dev);
|
||||||
|
|
||||||
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
exynos_drm_ipp_register(drm_dev, ipp, &ipp_funcs,
|
||||||
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
|
DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
|
||||||
|
@ -473,7 +472,7 @@ static void scaler_unbind(struct device *dev, struct device *master,
|
||||||
struct exynos_drm_ipp *ipp = &scaler->ipp;
|
struct exynos_drm_ipp *ipp = &scaler->ipp;
|
||||||
|
|
||||||
exynos_drm_ipp_unregister(drm_dev, ipp);
|
exynos_drm_ipp_unregister(drm_dev, ipp);
|
||||||
drm_iommu_detach_device(scaler->drm_dev, scaler->dev);
|
exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct component_ops scaler_component_ops = {
|
static const struct component_ops scaler_component_ops = {
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
#include "exynos_drm_crtc.h"
|
#include "exynos_drm_crtc.h"
|
||||||
#include "exynos_drm_fb.h"
|
#include "exynos_drm_fb.h"
|
||||||
#include "exynos_drm_plane.h"
|
#include "exynos_drm_plane.h"
|
||||||
#include "exynos_drm_iommu.h"
|
|
||||||
|
|
||||||
#define MIXER_WIN_NR 3
|
#define MIXER_WIN_NR 3
|
||||||
#define VP_DEFAULT_WIN 2
|
#define VP_DEFAULT_WIN 2
|
||||||
|
@ -381,19 +380,16 @@ static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height)
|
||||||
mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_SCAN_MASK);
|
mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_SCAN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
|
static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
|
enum hdmi_quantization_range range = drm_default_rgb_quant_range(mode);
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
switch (height) {
|
if (mode->vdisplay < 720) {
|
||||||
case 480:
|
val = MXR_CFG_RGB601;
|
||||||
case 576:
|
} else {
|
||||||
val = MXR_CFG_RGB601_0_255;
|
val = MXR_CFG_RGB709;
|
||||||
break;
|
|
||||||
case 720:
|
|
||||||
case 1080:
|
|
||||||
default:
|
|
||||||
val = MXR_CFG_RGB709_16_235;
|
|
||||||
/* Configure the BT.709 CSC matrix for full range RGB. */
|
/* Configure the BT.709 CSC matrix for full range RGB. */
|
||||||
mixer_reg_write(ctx, MXR_CM_COEFF_Y,
|
mixer_reg_write(ctx, MXR_CM_COEFF_Y,
|
||||||
MXR_CSC_CT( 0.184, 0.614, 0.063) |
|
MXR_CSC_CT( 0.184, 0.614, 0.063) |
|
||||||
|
@ -402,9 +398,13 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
|
||||||
MXR_CSC_CT(-0.102, -0.338, 0.440));
|
MXR_CSC_CT(-0.102, -0.338, 0.440));
|
||||||
mixer_reg_write(ctx, MXR_CM_COEFF_CR,
|
mixer_reg_write(ctx, MXR_CM_COEFF_CR,
|
||||||
MXR_CSC_CT( 0.440, -0.399, -0.040));
|
MXR_CSC_CT( 0.440, -0.399, -0.040));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (range == HDMI_QUANTIZATION_RANGE_FULL)
|
||||||
|
val |= MXR_CFG_QUANT_RANGE_FULL;
|
||||||
|
else
|
||||||
|
val |= MXR_CFG_QUANT_RANGE_LIMITED;
|
||||||
|
|
||||||
mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
|
mixer_reg_writemask(ctx, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +461,7 @@ static void mixer_commit(struct mixer_context *ctx)
|
||||||
struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
|
struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode;
|
||||||
|
|
||||||
mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay);
|
mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay);
|
||||||
mixer_cfg_rgb_fmt(ctx, mode->vdisplay);
|
mixer_cfg_rgb_fmt(ctx, mode);
|
||||||
mixer_run(ctx);
|
mixer_run(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,12 +878,12 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return drm_iommu_attach_device(drm_dev, mixer_ctx->dev);
|
return exynos_drm_register_dma(drm_dev, mixer_ctx->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
|
static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
|
||||||
{
|
{
|
||||||
drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
|
exynos_drm_unregister_dma(mixer_ctx->drm_dev, mixer_ctx->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
|
static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
|
||||||
|
|
|
@ -104,6 +104,7 @@
|
||||||
#define WINCONx_BURSTLEN_16WORD (0x0 << 10)
|
#define WINCONx_BURSTLEN_16WORD (0x0 << 10)
|
||||||
#define WINCONx_BURSTLEN_8WORD (0x1 << 10)
|
#define WINCONx_BURSTLEN_8WORD (0x1 << 10)
|
||||||
#define WINCONx_BURSTLEN_4WORD (0x2 << 10)
|
#define WINCONx_BURSTLEN_4WORD (0x2 << 10)
|
||||||
|
#define WINCONx_ALPHA_MUL_F (1 << 7)
|
||||||
#define WINCONx_BLD_PIX_F (1 << 6)
|
#define WINCONx_BLD_PIX_F (1 << 6)
|
||||||
#define WINCONx_BPPMODE_MASK (0xf << 2)
|
#define WINCONx_BPPMODE_MASK (0xf << 2)
|
||||||
#define WINCONx_BPPMODE_16BPP_565 (0x5 << 2)
|
#define WINCONx_BPPMODE_16BPP_565 (0x5 << 2)
|
||||||
|
@ -116,11 +117,15 @@
|
||||||
#define WINCONx_BPPMODE_16BPP_A4444 (0xe << 2)
|
#define WINCONx_BPPMODE_16BPP_A4444 (0xe << 2)
|
||||||
#define WINCONx_ALPHA_SEL_F (1 << 1)
|
#define WINCONx_ALPHA_SEL_F (1 << 1)
|
||||||
#define WINCONx_ENWIN_F (1 << 0)
|
#define WINCONx_ENWIN_F (1 << 0)
|
||||||
|
#define WINCONx_BLEND_MODE_MASK (0xc2)
|
||||||
|
|
||||||
/* SHADOWCON */
|
/* SHADOWCON */
|
||||||
#define SHADOWCON_PROTECT_MASK GENMASK(14, 10)
|
#define SHADOWCON_PROTECT_MASK GENMASK(14, 10)
|
||||||
#define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n)))
|
#define SHADOWCON_Wx_PROTECT(n) (1 << (10 + (n)))
|
||||||
|
|
||||||
|
/* VIDOSDxC */
|
||||||
|
#define VIDOSDxC_ALPHA0_RGB_MASK (0xffffff)
|
||||||
|
|
||||||
/* VIDOSDxD */
|
/* VIDOSDxD */
|
||||||
#define VIDOSD_Wx_ALPHA_R_F(n) (((n) & 0xff) << 16)
|
#define VIDOSD_Wx_ALPHA_R_F(n) (((n) & 0xff) << 16)
|
||||||
#define VIDOSD_Wx_ALPHA_G_F(n) (((n) & 0xff) << 8)
|
#define VIDOSD_Wx_ALPHA_G_F(n) (((n) & 0xff) << 8)
|
||||||
|
@ -206,4 +211,21 @@
|
||||||
#define CRCCTRL_CRCEN (0x1 << 0)
|
#define CRCCTRL_CRCEN (0x1 << 0)
|
||||||
#define CRCCTRL_MASK (0x7)
|
#define CRCCTRL_MASK (0x7)
|
||||||
|
|
||||||
|
/* BLENDCON */
|
||||||
|
#define BLEND_NEW (1 << 0)
|
||||||
|
|
||||||
|
/* BLENDERQx */
|
||||||
|
#define BLENDERQ_ZERO 0x0
|
||||||
|
#define BLENDERQ_ONE 0x1
|
||||||
|
#define BLENDERQ_ALPHA_A 0x2
|
||||||
|
#define BLENDERQ_ONE_MINUS_ALPHA_A 0x3
|
||||||
|
#define BLENDERQ_ALPHA0 0x6
|
||||||
|
#define BLENDERQ_Q_FUNC_F(n) (n << 18)
|
||||||
|
#define BLENDERQ_P_FUNC_F(n) (n << 12)
|
||||||
|
#define BLENDERQ_B_FUNC_F(n) (n << 6)
|
||||||
|
#define BLENDERQ_A_FUNC_F(n) (n << 0)
|
||||||
|
|
||||||
|
/* BLENDCON */
|
||||||
|
#define BLEND_NEW (1 << 0)
|
||||||
|
|
||||||
#endif /* EXYNOS_REGS_DECON5433_H */
|
#endif /* EXYNOS_REGS_DECON5433_H */
|
||||||
|
|
|
@ -85,10 +85,11 @@
|
||||||
/* bits for MXR_CFG */
|
/* bits for MXR_CFG */
|
||||||
#define MXR_CFG_LAYER_UPDATE (1 << 31)
|
#define MXR_CFG_LAYER_UPDATE (1 << 31)
|
||||||
#define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29)
|
#define MXR_CFG_LAYER_UPDATE_COUNT_MASK (3 << 29)
|
||||||
#define MXR_CFG_RGB601_0_255 (0 << 9)
|
#define MXR_CFG_QUANT_RANGE_FULL (0 << 9)
|
||||||
#define MXR_CFG_RGB601_16_235 (1 << 9)
|
#define MXR_CFG_QUANT_RANGE_LIMITED (1 << 9)
|
||||||
#define MXR_CFG_RGB709_0_255 (2 << 9)
|
#define MXR_CFG_RGB601 (0 << 10)
|
||||||
#define MXR_CFG_RGB709_16_235 (3 << 9)
|
#define MXR_CFG_RGB709 (1 << 10)
|
||||||
|
|
||||||
#define MXR_CFG_RGB_FMT_MASK 0x600
|
#define MXR_CFG_RGB_FMT_MASK 0x600
|
||||||
#define MXR_CFG_OUT_YUV444 (0 << 8)
|
#define MXR_CFG_OUT_YUV444 (0 << 8)
|
||||||
#define MXR_CFG_OUT_RGB888 (1 << 8)
|
#define MXR_CFG_OUT_RGB888 (1 << 8)
|
||||||
|
|
Loading…
Reference in a new issue