summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tegra/dc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r--drivers/gpu/drm/tegra/dc.c114
1 files changed, 68 insertions, 46 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index eb70eee8992a..01e9d5011dd8 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -7,10 +7,12 @@
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/iommu.h>
#include <linux/interconnect.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
@@ -21,9 +23,11 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_blend.h>
#include <drm/drm_debugfs.h>
#include <drm/drm_fourcc.h>
-#include <drm/drm_plane_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
#include "dc.h"
@@ -345,18 +349,19 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
{
unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
struct tegra_dc *dc = plane->dc;
- bool yuv, planar;
+ unsigned int planes;
u32 value;
+ bool yuv;
/*
* For YUV planar modes, the number of bytes per pixel takes into
* account only the luma component and therefore is 1.
*/
- yuv = tegra_plane_format_is_yuv(window->format, &planar, NULL);
+ yuv = tegra_plane_format_is_yuv(window->format, &planes, NULL);
if (!yuv)
bpp = window->bits_per_pixel / 8;
else
- bpp = planar ? 1 : 2;
+ bpp = (planes > 1) ? 1 : 2;
tegra_plane_writel(plane, window->format, DC_WIN_COLOR_DEPTH);
tegra_plane_writel(plane, window->swap, DC_WIN_BYTE_SWAP);
@@ -385,7 +390,7 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
* For DDA computations the number of bytes per pixel for YUV planar
* modes needs to take into account all Y, U and V components.
*/
- if (yuv && planar)
+ if (yuv && planes > 1)
bpp = 2;
h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp);
@@ -405,9 +410,12 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
tegra_plane_writel(plane, window->base[0], DC_WINBUF_START_ADDR);
- if (yuv && planar) {
+ if (yuv && planes > 1) {
tegra_plane_writel(plane, window->base[1], DC_WINBUF_START_ADDR_U);
- tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V);
+
+ if (planes > 2)
+ tegra_plane_writel(plane, window->base[2], DC_WINBUF_START_ADDR_V);
+
value = window->stride[1] << 16 | window->stride[0];
tegra_plane_writel(plane, value, DC_WIN_LINE_STRIDE);
} else {
@@ -1018,14 +1026,15 @@ static void tegra_cursor_atomic_disable(struct drm_plane *plane,
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
}
-static int tegra_cursor_atomic_async_check(struct drm_plane *plane, struct drm_atomic_state *state)
+static int tegra_cursor_atomic_async_check(struct drm_plane *plane, struct drm_atomic_state *state,
+ bool flip)
{
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_crtc_state *crtc_state;
int min_scale, max_scale;
int err;
- crtc_state = drm_atomic_get_existing_crtc_state(state, new_state->crtc);
+ crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;
@@ -1193,6 +1202,13 @@ static const u32 tegra114_overlay_formats[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_YUV420,
DRM_FORMAT_YUV422,
+ /* semi-planar formats */
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_NV24,
+ DRM_FORMAT_NV42,
};
static const u32 tegra124_overlay_formats[] = {
@@ -1221,8 +1237,18 @@ static const u32 tegra124_overlay_formats[] = {
/* planar formats */
DRM_FORMAT_UYVY,
DRM_FORMAT_YUYV,
- DRM_FORMAT_YUV420,
- DRM_FORMAT_YUV422,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_YUV420, /* YU12 */
+ DRM_FORMAT_YUV422, /* YU16 */
+ DRM_FORMAT_YUV444, /* YU24 */
+ /* semi-planar formats */
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_NV24,
+ DRM_FORMAT_NV42,
};
static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
@@ -1296,10 +1322,16 @@ static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm,
if (wgrp->dc == dc->pipe) {
for (j = 0; j < wgrp->num_windows; j++) {
unsigned int index = wgrp->windows[j];
+ enum drm_plane_type type;
+
+ if (primary)
+ type = DRM_PLANE_TYPE_OVERLAY;
+ else
+ type = DRM_PLANE_TYPE_PRIMARY;
plane = tegra_shared_plane_create(drm, dc,
wgrp->index,
- index);
+ index, type);
if (IS_ERR(plane))
return plane;
@@ -1307,10 +1339,8 @@ static struct drm_plane *tegra_dc_add_shared_planes(struct drm_device *drm,
* Choose the first shared plane owned by this
* head as the primary plane.
*/
- if (!primary) {
- plane->type = DRM_PLANE_TYPE_PRIMARY;
+ if (!primary)
primary = plane;
- }
}
}
}
@@ -1364,7 +1394,10 @@ static void tegra_crtc_reset(struct drm_crtc *crtc)
if (crtc->state)
tegra_crtc_atomic_destroy_state(crtc, crtc->state);
- __drm_atomic_helper_crtc_reset(crtc, &state->base);
+ if (state)
+ __drm_atomic_helper_crtc_reset(crtc, &state->base);
+ else
+ __drm_atomic_helper_crtc_reset(crtc, NULL);
}
static struct drm_crtc_state *
@@ -1722,8 +1755,15 @@ static void tegra_dc_early_unregister(struct drm_crtc *crtc)
unsigned int count = ARRAY_SIZE(debugfs_files);
struct drm_minor *minor = crtc->dev->primary;
struct tegra_dc *dc = to_tegra_dc(crtc);
+ struct dentry *root;
+
+#ifdef CONFIG_DEBUG_FS
+ root = crtc->debugfs_entry;
+#else
+ root = NULL;
+#endif
- drm_debugfs_remove_files(dc->debugfs_files, count, minor);
+ drm_debugfs_remove_files(dc->debugfs_files, count, root, minor);
kfree(dc->debugfs_files);
dc->debugfs_files = NULL;
}
@@ -2358,7 +2398,6 @@ static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc,
const struct tegra_plane_state *tegra_state;
const struct drm_plane_state *plane_state;
struct tegra_dc *dc = to_tegra_dc(crtc);
- const struct drm_crtc_state *old_state;
struct drm_crtc_state *new_state;
struct tegra_plane *tegra;
struct drm_plane *plane;
@@ -2373,7 +2412,6 @@ static int tegra_crtc_calculate_memory_bandwidth(struct drm_crtc *crtc,
return 0;
new_state = drm_atomic_get_new_crtc_state(state, crtc);
- old_state = drm_atomic_get_old_crtc_state(state, crtc);
/*
* For overlapping planes pixel's data is fetched for each plane at
@@ -3111,6 +3149,7 @@ static int tegra_dc_couple(struct tegra_dc *dc)
dc->client.parent = &parent->client;
dev_dbg(dc->dev, "coupled to %s\n", dev_name(companion));
+ put_device(companion);
}
return 0;
@@ -3182,8 +3221,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
usleep_range(2000, 4000);
err = reset_control_assert(dc->rst);
- if (err < 0)
+ if (err < 0) {
+ clk_disable_unprepare(dc->clk);
return err;
+ }
usleep_range(2000, 4000);
@@ -3211,16 +3252,9 @@ static int tegra_dc_probe(struct platform_device *pdev)
return -ENXIO;
err = tegra_dc_rgb_probe(dc);
- if (err < 0 && err != -ENODEV) {
- const char *level = KERN_ERR;
-
- if (err == -EPROBE_DEFER)
- level = KERN_DEBUG;
-
- dev_printk(level, dc->dev, "failed to probe RGB output: %d\n",
- err);
- return err;
- }
+ if (err < 0 && err != -ENODEV)
+ return dev_err_probe(&pdev->dev, err,
+ "failed to probe RGB output\n");
platform_set_drvdata(pdev, dc);
pm_runtime_enable(&pdev->dev);
@@ -3245,27 +3279,15 @@ disable_pm:
return err;
}
-static int tegra_dc_remove(struct platform_device *pdev)
+static void tegra_dc_remove(struct platform_device *pdev)
{
struct tegra_dc *dc = platform_get_drvdata(pdev);
- int err;
- err = host1x_client_unregister(&dc->client);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
- err);
- return err;
- }
+ host1x_client_unregister(&dc->client);
- err = tegra_dc_rgb_remove(dc);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to remove RGB output: %d\n", err);
- return err;
- }
+ tegra_dc_rgb_remove(dc);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
struct platform_driver tegra_dc_driver = {