drm/tegra: Properly align stride for framebuffers
authorThierry Reding <treding@nvidia.com>
Fri, 11 Jul 2014 06:29:14 +0000 (08:29 +0200)
committerThierry Reding <treding@nvidia.com>
Mon, 4 Aug 2014 08:07:38 +0000 (10:07 +0200)
Tegra20 and Tegra30 both required the buffer line stride to be aligned
on 8 byte boundaries. Tegra114 and Tegra124 increased the alignment to
64 bytes. Introduce a parameter to specify the alignment requirements
for each display controller and round up the pitch of newly allocated
framebuffers appropriately.

Originally-by: Stéphane Marchesin <marcheu@chromium.org>
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/fb.c
drivers/gpu/drm/tegra/gem.c

index afcca04f53674231e42ead899757fe69d5073071..8886907d44b0add3d1bd5aef4b3251865a653c10 100644 (file)
@@ -19,6 +19,7 @@ struct tegra_dc_soc_info {
        bool supports_interlacing;
        bool supports_cursor;
        bool supports_block_linear;
+       unsigned int pitch_align;
 };
 
 struct tegra_plane {
@@ -1283,12 +1284,20 @@ static int tegra_dc_init(struct host1x_client *client)
 {
        struct drm_device *drm = dev_get_drvdata(client->parent);
        struct tegra_dc *dc = host1x_client_to_dc(client);
+       struct tegra_drm *tegra = drm->dev_private;
        int err;
 
        drm_crtc_init(drm, &dc->base, &tegra_crtc_funcs);
        drm_mode_crtc_set_gamma_size(&dc->base, 256);
        drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
 
+       /*
+        * Keep track of the minimum pitch alignment across all display
+        * controllers.
+        */
+       if (dc->soc->pitch_align > tegra->pitch_align)
+               tegra->pitch_align = dc->soc->pitch_align;
+
        err = tegra_dc_rgb_init(drm, dc);
        if (err < 0 && err != -ENODEV) {
                dev_err(dc->dev, "failed to initialize RGB output: %d\n", err);
@@ -1347,18 +1356,28 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
        .supports_interlacing = false,
        .supports_cursor = false,
        .supports_block_linear = false,
+       .pitch_align = 8,
 };
 
 static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
        .supports_interlacing = false,
        .supports_cursor = false,
        .supports_block_linear = false,
+       .pitch_align = 8,
+};
+
+static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
+       .supports_interlacing = false,
+       .supports_cursor = false,
+       .supports_block_linear = false,
+       .pitch_align = 64,
 };
 
 static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
        .supports_interlacing = true,
        .supports_cursor = true,
        .supports_block_linear = true,
+       .pitch_align = 64,
 };
 
 static const struct of_device_id tegra_dc_of_match[] = {
index 96d754e7b3eb26b176f5e55fa5ca52d5efdafc73..e89c70fa82d554f3da8fced5ae99b840e56c985f 100644 (file)
@@ -45,6 +45,8 @@ struct tegra_drm {
 #ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_fbdev *fbdev;
 #endif
+
+       unsigned int pitch_align;
 };
 
 struct tegra_drm_client;
index 7790d43ad082e2a9fed72f7183e2e386277e1602..3513d12d5aa1447822a7ef57449799b1aff83df9 100644 (file)
@@ -194,6 +194,7 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
                             struct drm_fb_helper_surface_size *sizes)
 {
        struct tegra_fbdev *fbdev = to_tegra_fbdev(helper);
+       struct tegra_drm *tegra = helper->dev->dev_private;
        struct drm_device *drm = helper->dev;
        struct drm_mode_fb_cmd2 cmd = { 0 };
        unsigned int bytes_per_pixel;
@@ -208,7 +209,8 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper,
 
        cmd.width = sizes->surface_width;
        cmd.height = sizes->surface_height;
-       cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
+       cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
+                                 tegra->pitch_align);
        cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
                                                     sizes->surface_depth);
 
index c1e4e8b6e5ca77ddad5b214d6aefd3aee7c47175..2545c7a468a2f3c316729cfa731bf238f6eac73f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/dma-buf.h>
 #include <drm/tegra_drm.h>
 
+#include "drm.h"
 #include "gem.h"
 
 static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo)
@@ -259,8 +260,10 @@ int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
                         struct drm_mode_create_dumb *args)
 {
        int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+       struct tegra_drm *tegra = drm->dev_private;
        struct tegra_bo *bo;
 
+       min_pitch = round_up(min_pitch, tegra->pitch_align);
        if (args->pitch < min_pitch)
                args->pitch = min_pitch;