Commit fb878d10 authored by Dave Airlie's avatar Dave Airlie
Browse files

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

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: default avatarDave 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
parents 513126ae 13e810f1
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -10,11 +10,6 @@ config DRM_EXYNOS

if DRM_EXYNOS

config DRM_EXYNOS_IOMMU
	bool
	depends on EXYNOS_IOMMU
	default y

comment "CRTCs"

config DRM_EXYNOS_FIMD
+1 −2
Original line number Diff line number Diff line
@@ -4,10 +4,9 @@
# 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 \
		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_EXYNOS_IOMMU) += exynos_drm_iommu.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS5433_DECON)	+= exynos5433_drm_decon.o
exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON)	+= exynos7_drm_decon.o
+82 −5
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@
#include "exynos_drm_crtc.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_iommu.h"
#include "regs-decon5433.h"

#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,
};

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,
				  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);
}

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,
				 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;

	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 &= WINCONx_ENWIN_F;

@@ -279,7 +351,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win,
	case DRM_FORMAT_ARGB8888:
	default:
		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;
		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_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)
@@ -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].zpos = win - ctx->first_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,
					&ctx->configs[win]);
@@ -569,7 +646,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)

	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)
@@ -579,7 +656,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
	decon_disable(ctx->crtc);

	/* 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 = {
+2 −3
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@
#include "exynos_drm_plane.h"
#include "exynos_drm_drv.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_iommu.h"
#include "regs-decon7.h"

/*
@@ -133,13 +132,13 @@ static int decon_ctx_initialize(struct decon_context *ctx,

	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)
{
	/* 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,
+157 −0
Original line number Diff line number Diff line
/* 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.
 */
// 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"
#include "exynos_drm_iommu.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)
{
@@ -35,31 +46,6 @@ static inline void clear_dma_max_seg_size(struct device *dev)
	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
 *
@@ -69,7 +55,7 @@ void drm_release_iommu_mapping(struct drm_device *drm_dev)
 * This function should be called by sub drivers to attach it to iommu
 * mapping.
 */
int drm_iommu_attach_device(struct drm_device *drm_dev,
static int drm_iommu_attach_device(struct drm_device *drm_dev,
				struct device *subdrv_dev)
{
	struct exynos_drm_private *priv = drm_dev->dev_private;
@@ -85,7 +71,15 @@ int drm_iommu_attach_device(struct drm_device *drm_dev,
	if (ret)
		return ret;

	ret = __exynos_iommu_attach(priv, subdrv_dev);
	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);

@@ -101,11 +95,63 @@ int drm_iommu_attach_device(struct drm_device *drm_dev,
 * This function should be called by sub drivers to detach it from iommu
 * mapping
 */
void drm_iommu_detach_device(struct drm_device *drm_dev,
static 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);
	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;
}
Loading