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 ...
Цей коміт міститься в:
@@ -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 = {
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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++) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -49,56 +49,46 @@ struct scaler_context {
|
||||
const struct scaler_data *scaler_data;
|
||||
};
|
||||
|
||||
static u32 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;
|
||||
}
|
||||
struct scaler_format {
|
||||
u32 drm_fmt;
|
||||
u32 internal_fmt;
|
||||
u32 chroma_tile_w;
|
||||
u32 chroma_tile_h;
|
||||
};
|
||||
|
||||
return 0;
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
|
||||
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 = {
|
||||
|
@@ -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 ||
|
||||
|
@@ -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)
|
||||
|
Посилання в новій задачі
Заблокувати користувача