summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/exynos
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-10-28 17:49:53 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-28 17:49:53 -0700
commit53b3b6bbfde6aae8d1ededc86ad4e0e1e00eb5f8 (patch)
treeb29473f21270aefd113b298c9402be8b4b3c91b4 /drivers/gpu/drm/exynos
parent746bb4ed6d626f3f9e431a7f9b20504538e62ded (diff)
parentf2bfc71aee75feff33ca659322b72ffeed5a243d (diff)
Merge tag 'drm-next-2018-10-24' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie: "This is going to rebuild more than drm as it adds a new helper to list.h for doing bulk updates. Seemed like a reasonable addition to me. Otherwise the usual merge window stuff lots of i915 and amdgpu, not so much nouveau, and piles of everything else. Core: - Adds a new list.h helper for doing bulk list updates for TTM. - Don't leak fb address in smem_start to userspace (comes with EXPORT workaround for people using mali out of tree hacks) - udmabuf device to turn memfd regions into dma-buf - Per-plane blend mode property - ref/unref replacements with get/put - fbdev conflicting framebuffers code cleaned up - host-endian format variants - panel orientation quirk for Acer One 10 bridge: - TI SN65DSI86 chip support vkms: - GEM support. - Cursor support amdgpu: - Merge amdkfd and amdgpu into one module - CEC over DP AUX support - Picasso APU support + VCN dynamic powergating - Raven2 APU support - Vega20 enablement + kfd support - ACP powergating improvements - ABGR/XBGR display support - VCN jpeg support - xGMI support - DC i2c/aux cleanup - Ycbcr 4:2:0 support - GPUVM improvements - Powerplay and powerplay endian fixes - Display underflow fixes vmwgfx: - Move vmwgfx specific TTM code to vmwgfx - Split out vmwgfx buffer/resource validation code - Atomic operation rework bochs: - use more helpers - format/byteorder improvements qxl: - use more helpers i915: - GGTT coherency getparam - Turn off resource streamer API - More Icelake enablement + DMC firmware - Full PPGTT for Ivybridge, Haswell and Valleyview - DDB distribution based on resolution - Limited range DP display support nouveau: - CEC over DP AUX support - Initial HDMI 2.0 support virtio-gpu: - vmap support for PRIME objects tegra: - Initial Tegra194 support - DMA/IOMMU integration fixes msm: - a6xx perf improvements + clock prefix - GPU preemption optimisations - a6xx devfreq support - cursor support rockchip: - PX30 support - rgb output interface support mediatek: - HDMI output support on mt2701 and mt7623 rcar-du: - Interlaced modes on Gen3 - LVDS on R8A77980 - D3 and E3 SoC support hisilicon: - misc fixes mxsfb: - runtime pm support sun4i: - R40 TCON support - Allwinner A64 support - R40 HDMI support omapdrm: - Driver rework changing display pipeline ordering to use common code - DMM memory barrier and irq fixes - Errata workarounds exynos: - out-bridge support for LVDS bridge driver - Samsung 16x16 tiled format support - Plane alpha and pixel blend mode support tilcdc: - suspend/resume update mali-dp: - misc updates" * tag 'drm-next-2018-10-24' of git://anongit.freedesktop.org/drm/drm: (1382 commits) firmware/dmc/icl: Add missing MODULE_FIRMWARE() for Icelake. drm/i915/icl: Fix signal_levels drm/i915/icl: Fix DDI/TC port clk_off bits drm/i915/icl: create function to identify combophy port drm/i915/gen9+: Fix initial readout for Y tiled framebuffers drm/i915: Large page offsets for pread/pwrite drm/i915/selftests: Disable shrinker across mmap-exhaustion drm/i915/dp: Link train Fallback on eDP only if fallback link BW can fit panel's native mode drm/i915: Fix intel_dp_mst_best_encoder() drm/i915: Skip vcpi allocation for MSTB ports that are gone drm/i915: Don't unset intel_connector->mst_port drm/i915: Only reset seqno if actually idle drm/i915: Use the correct crtc when sanitizing plane mapping drm/i915: Restore vblank interrupts earlier drm/i915: Check fb stride against plane max stride drm/amdgpu/vcn:Fix uninitialized symbol error drm: panel-orientation-quirks: Add quirk for Acer One 10 (S1003) drm/amd/amdgpu: Fix debugfs error handling drm/amdgpu: Update gc_9_0 golden settings. drm/amd/powerplay: update PPtable with DC BTC and Tvr SocLimit fields ...
Diffstat (limited to 'drivers/gpu/drm/exynos')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c26
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c107
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c17
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.h10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c46
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c16
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_scaler.c137
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c56
-rw-r--r--drivers/gpu/drm/exynos/regs-mixer.h5
10 files changed, 234 insertions, 189 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index b599f74692e5..6f76baf4550a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -149,37 +149,15 @@ static struct drm_driver exynos_drm_driver = {
static int exynos_drm_suspend(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
- struct exynos_drm_private *private;
-
- if (!drm_dev)
- return 0;
-
- private = drm_dev->dev_private;
-
- drm_kms_helper_poll_disable(drm_dev);
- exynos_drm_fbdev_suspend(drm_dev);
- private->suspend_state = drm_atomic_helper_suspend(drm_dev);
- if (IS_ERR(private->suspend_state)) {
- exynos_drm_fbdev_resume(drm_dev);
- drm_kms_helper_poll_enable(drm_dev);
- return PTR_ERR(private->suspend_state);
- }
- return 0;
+ return drm_mode_config_helper_suspend(drm_dev);
}
static void exynos_drm_resume(struct device *dev)
{
struct drm_device *drm_dev = dev_get_drvdata(dev);
- struct exynos_drm_private *private;
-
- if (!drm_dev)
- return;
- private = drm_dev->dev_private;
- drm_atomic_helper_resume(drm_dev, private->suspend_state);
- exynos_drm_fbdev_resume(drm_dev);
- drm_kms_helper_poll_enable(drm_dev);
+ drm_mode_config_helper_resume(drm_dev);
}
static const struct dev_pm_ops exynos_drm_pm_ops = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index c737c4bd2c19..ec9604f1272b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -92,6 +92,8 @@ struct exynos_drm_plane {
#define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1)
#define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2)
#define EXYNOS_DRM_PLANE_CAP_TILE (1 << 3)
+#define EXYNOS_DRM_PLANE_CAP_PIX_BLEND (1 << 4)
+#define EXYNOS_DRM_PLANE_CAP_WIN_BLEND (1 << 5)
/*
* Exynos DRM plane configuration structure.
@@ -195,7 +197,6 @@ struct drm_exynos_file_private {
*/
struct exynos_drm_private {
struct drm_fb_helper *fb_helper;
- struct drm_atomic_state *suspend_state;
struct device *g2d_dev;
struct device *dma_dev;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 781b82c2c579..07af7758066d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -255,6 +255,7 @@ struct exynos_dsi {
struct mipi_dsi_host dsi_host;
struct drm_connector connector;
struct drm_panel *panel;
+ struct drm_bridge *out_bridge;
struct device *dev;
void __iomem *reg_base;
@@ -279,7 +280,7 @@ struct exynos_dsi {
struct list_head transfer_list;
const struct exynos_dsi_driver_data *driver_data;
- struct device_node *bridge_node;
+ struct device_node *in_bridge_node;
};
#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
@@ -1382,29 +1383,37 @@ static void exynos_dsi_enable(struct drm_encoder *encoder)
return;
pm_runtime_get_sync(dsi->dev);
-
dsi->state |= DSIM_STATE_ENABLED;
- ret = drm_panel_prepare(dsi->panel);
- if (ret < 0) {
- dsi->state &= ~DSIM_STATE_ENABLED;
- pm_runtime_put_sync(dsi->dev);
- return;
+ if (dsi->panel) {
+ ret = drm_panel_prepare(dsi->panel);
+ if (ret < 0)
+ goto err_put_sync;
+ } else {
+ drm_bridge_pre_enable(dsi->out_bridge);
}
exynos_dsi_set_display_mode(dsi);
exynos_dsi_set_display_enable(dsi, true);
- ret = drm_panel_enable(dsi->panel);
- if (ret < 0) {
- dsi->state &= ~DSIM_STATE_ENABLED;
- exynos_dsi_set_display_enable(dsi, false);
- drm_panel_unprepare(dsi->panel);
- pm_runtime_put_sync(dsi->dev);
- return;
+ if (dsi->panel) {
+ ret = drm_panel_enable(dsi->panel);
+ if (ret < 0)
+ goto err_display_disable;
+ } else {
+ drm_bridge_enable(dsi->out_bridge);
}
dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE;
+ return;
+
+err_display_disable:
+ exynos_dsi_set_display_enable(dsi, false);
+ drm_panel_unprepare(dsi->panel);
+
+err_put_sync:
+ dsi->state &= ~DSIM_STATE_ENABLED;
+ pm_runtime_put(dsi->dev);
}
static void exynos_dsi_disable(struct drm_encoder *encoder)
@@ -1417,11 +1426,11 @@ static void exynos_dsi_disable(struct drm_encoder *encoder)
dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE;
drm_panel_disable(dsi->panel);
+ drm_bridge_disable(dsi->out_bridge);
exynos_dsi_set_display_enable(dsi, false);
drm_panel_unprepare(dsi->panel);
-
+ drm_bridge_post_disable(dsi->out_bridge);
dsi->state &= ~DSIM_STATE_ENABLED;
-
pm_runtime_put_sync(dsi->dev);
}
@@ -1499,7 +1508,30 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
- struct drm_device *drm = dsi->connector.dev;
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_device *drm = encoder->dev;
+ struct drm_bridge *out_bridge;
+
+ out_bridge = of_drm_find_bridge(device->dev.of_node);
+ if (out_bridge) {
+ drm_bridge_attach(encoder, out_bridge, NULL);
+ dsi->out_bridge = out_bridge;
+ encoder->bridge = NULL;
+ } else {
+ int ret = exynos_dsi_create_connector(encoder);
+
+ if (ret) {
+ DRM_ERROR("failed to create connector ret = %d\n", ret);
+ drm_encoder_cleanup(encoder);
+ return ret;
+ }
+
+ dsi->panel = of_drm_find_panel(device->dev.of_node);
+ if (dsi->panel) {
+ drm_panel_attach(dsi->panel, &dsi->connector);
+ dsi->connector.status = connector_status_connected;
+ }
+ }
/*
* This is a temporary solution and should be made by more generic way.
@@ -1518,14 +1550,6 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
dsi->lanes = device->lanes;
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
- dsi->panel = of_drm_find_panel(device->dev.of_node);
- if (IS_ERR(dsi->panel))
- dsi->panel = NULL;
-
- if (dsi->panel) {
- drm_panel_attach(dsi->panel, &dsi->connector);
- dsi->connector.status = connector_status_connected;
- }
exynos_drm_crtc_get_by_type(drm, EXYNOS_DISPLAY_TYPE_LCD)->i80_mode =
!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO);
@@ -1541,19 +1565,21 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct exynos_dsi *dsi = host_to_dsi(host);
- struct drm_device *drm = dsi->connector.dev;
-
- mutex_lock(&drm->mode_config.mutex);
+ struct drm_device *drm = dsi->encoder.dev;
if (dsi->panel) {
+ mutex_lock(&drm->mode_config.mutex);
exynos_dsi_disable(&dsi->encoder);
drm_panel_detach(dsi->panel);
dsi->panel = NULL;
dsi->connector.status = connector_status_disconnected;
+ mutex_unlock(&drm->mode_config.mutex);
+ } else {
+ if (dsi->out_bridge->funcs->detach)
+ dsi->out_bridge->funcs->detach(dsi->out_bridge);
+ dsi->out_bridge = NULL;
}
- mutex_unlock(&drm->mode_config.mutex);
-
if (drm->mode_config.poll_enabled)
drm_kms_helper_hotplug_event(drm);
@@ -1634,7 +1660,7 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
if (ret < 0)
return ret;
- dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
+ dsi->in_bridge_node = of_graph_get_remote_node(node, DSI_PORT_IN, 0);
return 0;
}
@@ -1645,7 +1671,7 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
struct drm_encoder *encoder = dev_get_drvdata(dev);
struct exynos_dsi *dsi = encoder_to_dsi(encoder);
struct drm_device *drm_dev = data;
- struct drm_bridge *bridge;
+ struct drm_bridge *in_bridge;
int ret;
drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs,
@@ -1657,17 +1683,10 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
if (ret < 0)
return ret;
- ret = exynos_dsi_create_connector(encoder);
- if (ret) {
- DRM_ERROR("failed to create connector ret = %d\n", ret);
- drm_encoder_cleanup(encoder);
- return ret;
- }
-
- if (dsi->bridge_node) {
- bridge = of_drm_find_bridge(dsi->bridge_node);
- if (bridge)
- drm_bridge_attach(encoder, bridge, NULL);
+ if (dsi->in_bridge_node) {
+ in_bridge = of_drm_find_bridge(dsi->in_bridge_node);
+ if (in_bridge)
+ drm_bridge_attach(encoder, in_bridge, NULL);
}
return mipi_dsi_host_register(&dsi->dsi_host);
@@ -1786,7 +1805,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
{
struct exynos_dsi *dsi = platform_get_drvdata(pdev);
- of_node_put(dsi->bridge_node);
+ of_node_put(dsi->in_bridge_node);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 132dd52d0ac7..918dd2c82209 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -270,20 +270,3 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
private->fb_helper = NULL;
}
-void exynos_drm_fbdev_suspend(struct drm_device *dev)
-{
- struct exynos_drm_private *private = dev->dev_private;
-
- console_lock();
- drm_fb_helper_set_suspend(private->fb_helper, 1);
- console_unlock();
-}
-
-void exynos_drm_fbdev_resume(struct drm_device *dev)
-{
- struct exynos_drm_private *private = dev->dev_private;
-
- console_lock();
- drm_fb_helper_set_suspend(private->fb_helper, 0);
- console_unlock();
-}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.h b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
index b33847223a85..6840b6aadbc0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.h
@@ -19,8 +19,6 @@
int exynos_drm_fbdev_init(struct drm_device *dev);
void exynos_drm_fbdev_fini(struct drm_device *dev);
-void exynos_drm_fbdev_suspend(struct drm_device *drm);
-void exynos_drm_fbdev_resume(struct drm_device *drm);
#else
@@ -39,14 +37,6 @@ static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
#define exynos_drm_output_poll_changed (NULL)
-static inline void exynos_drm_fbdev_suspend(struct drm_device *drm)
-{
-}
-
-static inline void exynos_drm_fbdev_resume(struct drm_device *drm)
-{
-}
-
#endif
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 7ba414b52faa..ce15d46bfce8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -448,7 +448,7 @@ static void gsc_handle_irq(struct gsc_context *ctx, bool enable,
}
-static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)
+static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
{
u32 cfg;
@@ -514,6 +514,9 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt)
break;
}
+ if (tiled)
+ cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE);
+
gsc_write(cfg, GSC_IN_CON);
}
@@ -632,7 +635,7 @@ static void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id,
gsc_src_set_buf_seq(ctx, buf_id, true);
}
-static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)
+static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled)
{
u32 cfg;
@@ -698,6 +701,9 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt)
break;
}
+ if (tiled)
+ cfg |= (GSC_IN_TILE_C_16x8 | GSC_OUT_TILE_MODE);
+
gsc_write(cfg, GSC_OUT_CON);
}
@@ -1122,11 +1128,11 @@ static int gsc_commit(struct exynos_drm_ipp *ipp,
return ret;
}
- gsc_src_set_fmt(ctx, task->src.buf.fourcc);
+ gsc_src_set_fmt(ctx, task->src.buf.fourcc, task->src.buf.modifier);
gsc_src_set_transf(ctx, task->transform.rotation);
gsc_src_set_size(ctx, &task->src);
gsc_src_set_addr(ctx, 0, &task->src);
- gsc_dst_set_fmt(ctx, task->dst.buf.fourcc);
+ gsc_dst_set_fmt(ctx, task->dst.buf.fourcc, task->dst.buf.modifier);
gsc_dst_set_size(ctx, &task->dst);
gsc_dst_set_addr(ctx, 0, &task->dst);
gsc_set_prescaler(ctx, &ctx->sc, &task->src.rect, &task->dst.rect);
@@ -1200,6 +1206,10 @@ static const unsigned int gsc_formats[] = {
DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422,
};
+static const unsigned int gsc_tiled_formats[] = {
+ DRM_FORMAT_NV12, DRM_FORMAT_NV21,
+};
+
static int gsc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1207,23 +1217,24 @@ static int gsc_probe(struct platform_device *pdev)
struct exynos_drm_ipp_formats *formats;
struct gsc_context *ctx;
struct resource *res;
- int ret, i;
+ int num_formats, ret, i, j;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
- formats = devm_kcalloc(dev,
- ARRAY_SIZE(gsc_formats), sizeof(*formats),
- GFP_KERNEL);
- if (!formats)
- return -ENOMEM;
-
driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev);
ctx->dev = dev;
ctx->num_clocks = driver_data->num_clocks;
ctx->clk_names = driver_data->clk_names;
+ /* construct formats/limits array */
+ num_formats = ARRAY_SIZE(gsc_formats) + ARRAY_SIZE(gsc_tiled_formats);
+ formats = devm_kcalloc(dev, num_formats, sizeof(*formats), GFP_KERNEL);
+ if (!formats)
+ return -ENOMEM;
+
+ /* linear formats */
for (i = 0; i < ARRAY_SIZE(gsc_formats); i++) {
formats[i].fourcc = gsc_formats[i];
formats[i].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
@@ -1231,8 +1242,19 @@ static int gsc_probe(struct platform_device *pdev)
formats[i].limits = driver_data->limits;
formats[i].num_limits = driver_data->num_limits;
}
+
+ /* tiled formats */
+ for (j = i, i = 0; i < ARRAY_SIZE(gsc_tiled_formats); j++, i++) {
+ formats[j].fourcc = gsc_tiled_formats[i];
+ formats[j].modifier = DRM_FORMAT_MOD_SAMSUNG_16_16_TILE;
+ formats[j].type = DRM_EXYNOS_IPP_FORMAT_SOURCE |
+ DRM_EXYNOS_IPP_FORMAT_DESTINATION;
+ formats[j].limits = driver_data->limits;
+ formats[j].num_limits = driver_data->num_limits;
+ }
+
ctx->formats = formats;
- ctx->num_formats = ARRAY_SIZE(gsc_formats);
+ ctx->num_formats = num_formats;
/* clock control */
for (i = 0; i < ctx->num_clocks; i++) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index dba29aec59b4..df0508e0e49e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -131,16 +131,14 @@ static void exynos_drm_plane_reset(struct drm_plane *plane)
if (plane->state) {
exynos_state = to_exynos_plane_state(plane->state);
- if (exynos_state->base.fb)
- drm_framebuffer_put(exynos_state->base.fb);
+ __drm_atomic_helper_plane_destroy_state(plane->state);
kfree(exynos_state);
plane->state = NULL;
}
exynos_state = kzalloc(sizeof(*exynos_state), GFP_KERNEL);
if (exynos_state) {
- plane->state = &exynos_state->base;
- plane->state->plane = plane;
+ __drm_atomic_helper_plane_reset(plane, &exynos_state->base);
plane->state->zpos = exynos_plane->config->zpos;
}
}
@@ -300,6 +298,10 @@ int exynos_plane_init(struct drm_device *dev,
const struct exynos_drm_plane_config *config)
{
int err;
+ unsigned int supported_modes = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+ BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE);
+ struct drm_plane *plane = &exynos_plane->base;
err = drm_universal_plane_init(dev, &exynos_plane->base,
1 << dev->mode_config.num_crtc,
@@ -320,5 +322,11 @@ int exynos_plane_init(struct drm_device *dev,
exynos_plane_attach_zpos_property(&exynos_plane->base, config->zpos,
!(config->capabilities & EXYNOS_DRM_PLANE_CAP_ZPOS));
+ if (config->capabilities & EXYNOS_DRM_PLANE_CAP_PIX_BLEND)
+ drm_plane_create_blend_mode_property(plane, supported_modes);
+
+ if (config->capabilities & EXYNOS_DRM_PLANE_CAP_WIN_BLEND)
+ drm_plane_create_alpha_property(plane);
+
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
index 0ddb6eec7b11..cd66774e817d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c
@@ -49,56 +49,46 @@ struct scaler_context {
const struct scaler_data *scaler_data;
};
-static u32 scaler_get_format(u32 drm_fmt)
+struct scaler_format {
+ u32 drm_fmt;
+ u32 internal_fmt;
+ u32 chroma_tile_w;
+ u32 chroma_tile_h;
+};
+
+static const struct scaler_format scaler_formats[] = {
+ { DRM_FORMAT_NV12, SCALER_YUV420_2P_UV, 8, 8 },
+ { DRM_FORMAT_NV21, SCALER_YUV420_2P_VU, 8, 8 },
+ { DRM_FORMAT_YUV420, SCALER_YUV420_3P, 8, 8 },
+ { DRM_FORMAT_YUYV, SCALER_YUV422_1P_YUYV, 16, 16 },
+ { DRM_FORMAT_UYVY, SCALER_YUV422_1P_UYVY, 16, 16 },
+ { DRM_FORMAT_YVYU, SCALER_YUV422_1P_YVYU, 16, 16 },
+ { DRM_FORMAT_NV16, SCALER_YUV422_2P_UV, 8, 16 },
+ { DRM_FORMAT_NV61, SCALER_YUV422_2P_VU, 8, 16 },
+ { DRM_FORMAT_YUV422, SCALER_YUV422_3P, 8, 16 },
+ { DRM_FORMAT_NV24, SCALER_YUV444_2P_UV, 16, 16 },
+ { DRM_FORMAT_NV42, SCALER_YUV444_2P_VU, 16, 16 },
+ { DRM_FORMAT_YUV444, SCALER_YUV444_3P, 16, 16 },
+ { DRM_FORMAT_RGB565, SCALER_RGB_565, 0, 0 },
+ { DRM_FORMAT_XRGB1555, SCALER_ARGB1555, 0, 0 },
+ { DRM_FORMAT_ARGB1555, SCALER_ARGB1555, 0, 0 },
+ { DRM_FORMAT_XRGB4444, SCALER_ARGB4444, 0, 0 },
+ { DRM_FORMAT_ARGB4444, SCALER_ARGB4444, 0, 0 },
+ { DRM_FORMAT_XRGB8888, SCALER_ARGB8888, 0, 0 },
+ { DRM_FORMAT_ARGB8888, SCALER_ARGB8888, 0, 0 },
+ { DRM_FORMAT_RGBX8888, SCALER_RGBA8888, 0, 0 },
+ { DRM_FORMAT_RGBA8888, SCALER_RGBA8888, 0, 0 },
+};
+
+static const struct scaler_format *scaler_get_format(u32 drm_fmt)
{
- switch (drm_fmt) {
- case DRM_FORMAT_NV12:
- return SCALER_YUV420_2P_UV;
- case DRM_FORMAT_NV21:
- return SCALER_YUV420_2P_VU;
- case DRM_FORMAT_YUV420:
- return SCALER_YUV420_3P;
- case DRM_FORMAT_YUYV:
- return SCALER_YUV422_1P_YUYV;
- case DRM_FORMAT_UYVY:
- return SCALER_YUV422_1P_UYVY;
- case DRM_FORMAT_YVYU:
- return SCALER_YUV422_1P_YVYU;
- case DRM_FORMAT_NV16:
- return SCALER_YUV422_2P_UV;
- case DRM_FORMAT_NV61:
- return SCALER_YUV422_2P_VU;
- case DRM_FORMAT_YUV422:
- return SCALER_YUV422_3P;
- case DRM_FORMAT_NV24:
- return SCALER_YUV444_2P_UV;
- case DRM_FORMAT_NV42:
- return SCALER_YUV444_2P_VU;
- case DRM_FORMAT_YUV444:
- return SCALER_YUV444_3P;
- case DRM_FORMAT_RGB565:
- return SCALER_RGB_565;
- case DRM_FORMAT_XRGB1555:
- return SCALER_ARGB1555;
- case DRM_FORMAT_ARGB1555:
- return SCALER_ARGB1555;
- case DRM_FORMAT_XRGB4444:
- return SCALER_ARGB4444;
- case DRM_FORMAT_ARGB4444:
- return SCALER_ARGB4444;
- case DRM_FORMAT_XRGB8888:
- return SCALER_ARGB8888;
- case DRM_FORMAT_ARGB8888:
- return SCALER_ARGB8888;
- case DRM_FORMAT_RGBX8888:
- return SCALER_RGBA8888;
- case DRM_FORMAT_RGBA8888:
- return SCALER_RGBA8888;
- default:
- break;
- }
+ int i;
- return 0;
+ for (i = 0; i < ARRAY_SIZE(scaler_formats); i++)
+ if (scaler_formats[i].drm_fmt == drm_fmt)
+ return &scaler_formats[i];
+
+ return NULL;
}
static inline int scaler_reset(struct scaler_context *scaler)
@@ -152,11 +142,11 @@ static inline void scaler_enable_int(struct scaler_context *scaler)
}
static inline void scaler_set_src_fmt(struct scaler_context *scaler,
- u32 src_fmt)
+ u32 src_fmt, u32 tile)
{
u32 val;
- val = SCALER_SRC_CFG_SET_COLOR_FORMAT(src_fmt);
+ val = SCALER_SRC_CFG_SET_COLOR_FORMAT(src_fmt) | (tile << 10);
scaler_write(val, SCALER_SRC_CFG);
}
@@ -188,15 +178,20 @@ static inline void scaler_set_src_span(struct scaler_context *scaler,
scaler_write(val, SCALER_SRC_SPAN);
}
-static inline void scaler_set_src_luma_pos(struct scaler_context *scaler,
- struct drm_exynos_ipp_task_rect *src_pos)
+static inline void scaler_set_src_luma_chroma_pos(struct scaler_context *scaler,
+ struct drm_exynos_ipp_task_rect *src_pos,
+ const struct scaler_format *fmt)
{
u32 val;
val = SCALER_SRC_Y_POS_SET_YH_POS(src_pos->x << 2);
val |= SCALER_SRC_Y_POS_SET_YV_POS(src_pos->y << 2);
scaler_write(val, SCALER_SRC_Y_POS);
- scaler_write(val, SCALER_SRC_C_POS); /* ATTENTION! */
+ val = SCALER_SRC_C_POS_SET_CH_POS(
+ (src_pos->x * fmt->chroma_tile_w / 16) << 2);
+ val |= SCALER_SRC_C_POS_SET_CV_POS(
+ (src_pos->y * fmt->chroma_tile_h / 16) << 2);
+ scaler_write(val, SCALER_SRC_C_POS);
}
static inline void scaler_set_src_wh(struct scaler_context *scaler,
@@ -366,11 +361,12 @@ static int scaler_commit(struct exynos_drm_ipp *ipp,
struct scaler_context *scaler =
container_of(ipp, struct scaler_context, ipp);
- u32 src_fmt = scaler_get_format(task->src.buf.fourcc);
struct drm_exynos_ipp_task_rect *src_pos = &task->src.rect;
-
- u32 dst_fmt = scaler_get_format(task->dst.buf.fourcc);
struct drm_exynos_ipp_task_rect *dst_pos = &task->dst.rect;
+ const struct scaler_format *src_fmt, *dst_fmt;
+
+ src_fmt = scaler_get_format(task->src.buf.fourcc);
+ dst_fmt = scaler_get_format(task->dst.buf.fourcc);
pm_runtime_get_sync(scaler->dev);
if (scaler_reset(scaler)) {
@@ -380,13 +376,14 @@ static int scaler_commit(struct exynos_drm_ipp *ipp,
scaler->task = task;
- scaler_set_src_fmt(scaler, src_fmt);
+ scaler_set_src_fmt(
+ scaler, src_fmt->internal_fmt, task->src.buf.modifier != 0);
scaler_set_src_base(scaler, &task->src);
scaler_set_src_span(scaler, &task->src);
- scaler_set_src_luma_pos(scaler, src_pos);
+ scaler_set_src_luma_chroma_pos(scaler, src_pos, src_fmt);
scaler_set_src_wh(scaler, src_pos);
- scaler_set_dst_fmt(scaler, dst_fmt);
+ scaler_set_dst_fmt(scaler, dst_fmt->internal_fmt);
scaler_set_dst_base(scaler, &task->dst);
scaler_set_dst_span(scaler, &task->dst);
scaler_set_dst_luma_pos(scaler, dst_pos);
@@ -617,6 +614,16 @@ static const struct drm_exynos_ipp_limit scaler_5420_one_pixel_limits[] = {
.v = { 65536 * 1 / 4, 65536 * 16 }) },
};
+static const struct drm_exynos_ipp_limit scaler_5420_tile_limits[] = {
+ { IPP_SIZE_LIMIT(BUFFER, .h = { 16, SZ_8K }, .v = { 16, SZ_8K })},
+ { IPP_SIZE_LIMIT(AREA, .h.align = 16, .v.align = 16) },
+ { IPP_SCALE_LIMIT(.h = {1, 1}, .v = {1, 1})},
+ { }
+};
+
+#define IPP_SRCDST_TILE_FORMAT(f, l) \
+ IPP_SRCDST_MFORMAT(f, DRM_FORMAT_MOD_SAMSUNG_16_16_TILE, (l))
+
static const struct exynos_drm_ipp_formats exynos5420_formats[] = {
/* SCALER_YUV420_2P_UV */
{ IPP_SRCDST_FORMAT(NV21, scaler_5420_two_pixel_hv_limits) },
@@ -680,6 +687,18 @@ static const struct exynos_drm_ipp_formats exynos5420_formats[] = {
/* SCALER_RGBA8888 */
{ IPP_SRCDST_FORMAT(RGBA8888, scaler_5420_one_pixel_limits) },
+
+ /* SCALER_YUV420_2P_UV TILE */
+ { IPP_SRCDST_TILE_FORMAT(NV21, scaler_5420_tile_limits) },
+
+ /* SCALER_YUV420_2P_VU TILE */
+ { IPP_SRCDST_TILE_FORMAT(NV12, scaler_5420_tile_limits) },
+
+ /* SCALER_YUV420_3P TILE */
+ { IPP_SRCDST_TILE_FORMAT(YUV420, scaler_5420_tile_limits) },
+
+ /* SCALER_YUV422_1P_YUYV TILE */
+ { IPP_SRCDST_TILE_FORMAT(YUYV, scaler_5420_tile_limits) },
};
static const struct scaler_data exynos5420_data = {
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index ffbf4a950f69..e3a4ecbc503b 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -131,14 +131,18 @@ static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
.pixel_formats = mixer_formats,
.num_pixel_formats = ARRAY_SIZE(mixer_formats),
.capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
- EXYNOS_DRM_PLANE_CAP_ZPOS,
+ EXYNOS_DRM_PLANE_CAP_ZPOS |
+ EXYNOS_DRM_PLANE_CAP_PIX_BLEND |
+ EXYNOS_DRM_PLANE_CAP_WIN_BLEND,
}, {
.zpos = 1,
.type = DRM_PLANE_TYPE_CURSOR,
.pixel_formats = mixer_formats,
.num_pixel_formats = ARRAY_SIZE(mixer_formats),
.capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE |
- EXYNOS_DRM_PLANE_CAP_ZPOS,
+ EXYNOS_DRM_PLANE_CAP_ZPOS |
+ EXYNOS_DRM_PLANE_CAP_PIX_BLEND |
+ EXYNOS_DRM_PLANE_CAP_WIN_BLEND,
}, {
.zpos = 2,
.type = DRM_PLANE_TYPE_OVERLAY,
@@ -146,7 +150,8 @@ static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = {
.num_pixel_formats = ARRAY_SIZE(vp_formats),
.capabilities = EXYNOS_DRM_PLANE_CAP_SCALE |
EXYNOS_DRM_PLANE_CAP_ZPOS |
- EXYNOS_DRM_PLANE_CAP_TILE,
+ EXYNOS_DRM_PLANE_CAP_TILE |
+ EXYNOS_DRM_PLANE_CAP_WIN_BLEND,
},
};
@@ -309,31 +314,42 @@ static void vp_default_filter(struct mixer_context *ctx)
}
static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win,
- bool alpha)
+ unsigned int pixel_alpha, unsigned int alpha)
{
+ u32 win_alpha = alpha >> 8;
u32 val;
val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
- if (alpha) {
- /* blending based on pixel alpha */
+ switch (pixel_alpha) {
+ case DRM_MODE_BLEND_PIXEL_NONE:
+ break;
+ case DRM_MODE_BLEND_COVERAGE:
+ val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
+ break;
+ case DRM_MODE_BLEND_PREMULTI:
+ default:
val |= MXR_GRP_CFG_BLEND_PRE_MUL;
val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
+ break;
+ }
+
+ if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
+ val |= MXR_GRP_CFG_WIN_BLEND_EN;
+ val |= win_alpha;
}
mixer_reg_writemask(ctx, MXR_GRAPHIC_CFG(win),
val, MXR_GRP_CFG_MISC_MASK);
}
-static void mixer_cfg_vp_blend(struct mixer_context *ctx)
+static void mixer_cfg_vp_blend(struct mixer_context *ctx, unsigned int alpha)
{
- u32 val;
+ u32 win_alpha = alpha >> 8;
+ u32 val = 0;
- /*
- * No blending at the moment since the NV12/NV21 pixelformats don't
- * have an alpha channel. However the mixer supports a global alpha
- * value for a layer. Once this functionality is exposed, we can
- * support blending of the video layer through this.
- */
- val = 0;
+ if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
+ val |= MXR_VID_CFG_BLEND_EN;
+ val |= win_alpha;
+ }
mixer_reg_write(ctx, MXR_VIDEO_CFG, val);
}
@@ -529,7 +545,7 @@ static void vp_video_buffer(struct mixer_context *ctx,
vp_reg_write(ctx, VP_BOT_C_PTR, chroma_addr[1]);
mixer_cfg_layer(ctx, plane->index, priority, true);
- mixer_cfg_vp_blend(ctx);
+ mixer_cfg_vp_blend(ctx, state->base.alpha);
spin_unlock_irqrestore(&ctx->reg_slock, flags);
@@ -553,10 +569,16 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
unsigned int win = plane->index;
unsigned int x_ratio = 0, y_ratio = 0;
unsigned int dst_x_offset, dst_y_offset;
+ unsigned int pixel_alpha;
dma_addr_t dma_addr;
unsigned int fmt;
u32 val;
+ if (fb->format->has_alpha)
+ pixel_alpha = state->base.pixel_blend_mode;
+ else
+ pixel_alpha = DRM_MODE_BLEND_PIXEL_NONE;
+
switch (fb->format->format) {
case DRM_FORMAT_XRGB4444:
case DRM_FORMAT_ARGB4444:
@@ -616,7 +638,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx,
mixer_reg_write(ctx, MXR_GRAPHIC_BASE(win), dma_addr);
mixer_cfg_layer(ctx, win, priority, true);
- mixer_cfg_gfx_blend(ctx, win, fb->format->has_alpha);
+ mixer_cfg_gfx_blend(ctx, win, pixel_alpha, state->base.alpha);
/* layer update mandatory for mixer 16.0.33.0 */
if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h
index 189cfa2470a8..d2b8194a07bf 100644
--- a/drivers/gpu/drm/exynos/regs-mixer.h
+++ b/drivers/gpu/drm/exynos/regs-mixer.h
@@ -109,12 +109,15 @@
#define MXR_CFG_SCAN_HD (1 << 0)
#define MXR_CFG_SCAN_MASK 0x47
+/* bits for MXR_VIDEO_CFG */
+#define MXR_VID_CFG_BLEND_EN (1 << 16)
+
/* bits for MXR_GRAPHICn_CFG */
#define MXR_GRP_CFG_COLOR_KEY_DISABLE (1 << 21)
#define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20)
#define MXR_GRP_CFG_WIN_BLEND_EN (1 << 17)
#define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16)
-#define MXR_GRP_CFG_MISC_MASK ((3 << 16) | (3 << 20))
+#define MXR_GRP_CFG_MISC_MASK ((3 << 16) | (3 << 20) | 0xff)
#define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8)
#define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0)
#define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0)