video: tegra: add utility function to compute framebuffer stride
Gary King [Sun, 15 Aug 2010 18:26:49 +0000 (11:26 -0700)]
framebuffers will generally not be exactly width * bpp / 8 bytes wide;
on tegra, linearly-addressed framebuffers will generally be rounded
up so that the stride is a multiple of 16B (so that they are compatible
with rendering from the hardware engines), and tiled framebuffers
will be a multiple of the tile width (64B).

add a utility function to tegra_dc to compute the correct stride
given a width, bpp and pixel layout, and use this in set_par.

Change-Id: I803a55b49c12476f20d5644707899c3fe1336c2d
Signed-off-by: Gary King <gking@nvidia.com>

arch/arm/mach-tegra/include/mach/dc.h
drivers/video/tegra/dc/dc.c
drivers/video/tegra/fb.c

index ae0273c..ce562e5 100644 (file)
 #define TEGRA_MAX_DC           2
 #define DC_N_WINDOWS           3
 
+#define TEGRA_DC_PITCH_ATOM    16
+#define TEGRA_DC_TILED_ATOM    16
+
+enum tegra_win_layout {
+       TEGRA_WIN_LAYOUT_PITCH,
+       TEGRA_WIN_LAYOUT_TILED,
+       TEGRA_WIN_LAYOUT_LINEAR_TILED,
+};
+
 struct tegra_dc_mode {
        int     pclk;
        int     h_ref_to_sync;
@@ -95,6 +104,7 @@ struct tegra_dc_win {
        unsigned                out_w;
        unsigned                out_h;
        unsigned                z;
+       enum tegra_win_layout   layout;
 
        int                     dirty;
        struct tegra_dc         *dc;
@@ -163,4 +173,7 @@ int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n);
 
 int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode);
 
+ssize_t tegra_dc_compute_stride(int xres, int bpp,
+                               enum tegra_win_layout layout);
+
 #endif
index 55ecf10..fadecf4 100644 (file)
@@ -325,6 +325,20 @@ struct tegra_dc *tegra_dc_get_dc(unsigned idx)
 }
 EXPORT_SYMBOL(tegra_dc_get_dc);
 
+ssize_t tegra_dc_compute_stride(int xres, int bpp, enum tegra_win_layout layout)
+{
+       unsigned int raw_stride = (xres * bpp) / 8;
+       unsigned int k, n = 0;
+
+       if (layout == TEGRA_WIN_LAYOUT_PITCH)
+               return ALIGN(raw_stride, TEGRA_DC_PITCH_ATOM);
+       else if (layout == TEGRA_WIN_LAYOUT_TILED)
+               return ALIGN(raw_stride, TEGRA_DC_TILED_ATOM);
+       else
+               return -EINVAL;
+}
+EXPORT_SYMBOL(tegra_dc_compute_stride);
+
 struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
 {
        if (win >= dc->n_windows)
index ac07c55..7e4ffa8 100644 (file)
@@ -113,7 +113,10 @@ static int tegra_fb_set_par(struct fb_info *info)
        default:
                return -EINVAL;
        }
-       info->fix.line_length = var->xres * var->bits_per_pixel / 8;
+
+       info->fix.line_length = tegra_dc_compute_stride(var->xres,
+                       var->bits_per_pixel, TEGRA_WIN_LAYOUT_PITCH);
+       tegra_fb->win->stride = info->fix.line_length;
 
        if (var->pixclock) {
                struct tegra_dc_mode mode;
@@ -371,7 +374,9 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
        win->z = 0;
        win->phys_addr = fb_phys;
        win->virt_addr = fb_base;
-       win->stride = fb_data->xres * fb_data->bits_per_pixel / 8;
+       win->layout = TEGRA_WIN_LAYOUT_PITCH;
+       win->stride = tegra_dc_compute_stride(fb_data->xres,
+                                     fb_data->bits_per_pixel, win->layout);
        win->flags = TEGRA_WIN_FLAG_ENABLED;
 
        if (fb_mem)