video: tegra: dc: Add display feature table support.
Kevin Huang [Mon, 7 May 2012 08:47:52 +0000 (01:47 -0700)]
Add display feature table so that user and kernel could set and
update window attributes properly.

Bug 962353

Change-Id: I08490a225892660126f3eefe4d5b7a4bb61d9bf7
Signed-off-by: Kevin Huang <kevinh@nvidia.com>
Reviewed-on: http://git-master/r/101078
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

drivers/video/tegra/dc/Makefile
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_config.c [new file with mode: 0644]
drivers/video/tegra/dc/dc_config.h [new file with mode: 0644]
drivers/video/tegra/dc/dc_priv.h
drivers/video/tegra/dc/ext/dev.c

index 01f1391..ebe9e89 100644 (file)
@@ -7,4 +7,5 @@ obj-y += edid.o
 obj-y += nvsd.o
 obj-y += dsi.o
 obj-y += dc_sysfs.o
+obj-y += dc_config.o
 obj-$(CONFIG_TEGRA_DC_EXTENSIONS) += ext/
index c42df4c..063d12e 100644 (file)
@@ -49,6 +49,7 @@
 #include <mach/latency_allowance.h>
 
 #include "dc_reg.h"
+#include "dc_config.h"
 #include "dc_priv.h"
 #include "nvsd.h"
 
@@ -93,25 +94,14 @@ struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
 DEFINE_MUTEX(tegra_dc_lock);
 DEFINE_MUTEX(shared_lock);
 
-static const struct {
-       bool h;
-       bool v;
-} can_filter[] = {
-       /* Window A has no filtering */
-       { false, false },
-       /* Window B has both H and V filtering */
-       { true,  true  },
-       /* Window C has only H filtering */
-       { false, true  },
-};
-static inline bool win_use_v_filter(const struct tegra_dc_win *win)
+static inline bool win_use_v_filter(struct tegra_dc *dc, const struct tegra_dc_win *win)
 {
-       return can_filter[win->idx].v &&
+       return tegra_dc_feature_has_filter(dc, win->idx, HAS_V_FILTER) &&
                win->h.full != dfixed_const(win->out_h);
 }
-static inline bool win_use_h_filter(const struct tegra_dc_win *win)
+static inline bool win_use_h_filter(struct tegra_dc *dc, const struct tegra_dc_win *win)
 {
-       return can_filter[win->idx].h &&
+       return tegra_dc_feature_has_filter(dc, win->idx, HAS_H_FILTER) &&
                win->w.full != dfixed_const(win->out_w);
 }
 
@@ -902,7 +892,7 @@ static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
 
        /* tegra_dc_get_bandwidth() treats V filter windows as double
         * bandwidth, but LA has a seperate client for V filter */
-       if (w->idx == 1 && win_use_v_filter(w))
+       if (w->idx == 1 && win_use_v_filter(dc, w))
                bw /= 2;
 
        /* our bandwidth is in kbytes/sec, but LA takes MBps.
@@ -1020,7 +1010,7 @@ static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
         * is of the luma plane's size only. */
        bpp = tegra_dc_is_yuv_planar(w->fmt) ?
                2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt);
-       ret = dc->mode.pclk / 1000UL * bpp / 8 * (win_use_v_filter(w) ? 2 : 1)
+       ret = dc->mode.pclk / 1000UL * bpp / 8 * (win_use_v_filter(dc, w) ? 2 : 1)
                * dfixed_trunc(w->w) / w->out_w *
                (WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1);
        /*
@@ -1205,8 +1195,8 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
                /* Bytes per pixel of bandwidth, used for dda_inc calculation */
                unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1);
-               const bool filter_h = win_use_h_filter(win);
-               const bool filter_v = win_use_v_filter(win);
+               const bool filter_h = win_use_h_filter(dc, win);
+               const bool filter_v = win_use_v_filter(dc, win);
 
                if (win->z != dc->blend.z[win->idx]) {
                        dc->blend.z[win->idx] = win->z;
@@ -1239,19 +1229,22 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                tegra_dc_writel(dc,
                                V_SIZE(win->out_h) | H_SIZE(win->out_w),
                                DC_WIN_SIZE);
-               tegra_dc_writel(dc,
-                               V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
-                               H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
-                               DC_WIN_PRESCALED_SIZE);
-
-               h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
-               v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
-               tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
-                               DC_WIN_DDA_INCREMENT);
-               h_dda = compute_initial_dda(win->x);
-               v_dda = compute_initial_dda(win->y);
-               tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
-               tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+
+               if (tegra_dc_feature_has_scaling(dc, win->idx)) {
+                       tegra_dc_writel(dc,
+                                       V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
+                                       H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
+                                       DC_WIN_PRESCALED_SIZE);
+
+                       h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
+                       v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
+                       tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
+                                       DC_WIN_DDA_INCREMENT);
+                       h_dda = compute_initial_dda(win->x);
+                       v_dda = compute_initial_dda(win->y);
+                       tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
+                       tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
+               }
 
                tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
                tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
@@ -1289,16 +1282,18 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
                tegra_dc_writel(dc, dfixed_trunc(v_offset),
                                DC_WINBUF_ADDR_V_OFFSET);
 
-               if (WIN_IS_TILED(win))
-                       tegra_dc_writel(dc,
-                                       DC_WIN_BUFFER_ADDR_MODE_TILE |
-                                       DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
-                                       DC_WIN_BUFFER_ADDR_MODE);
-               else
-                       tegra_dc_writel(dc,
-                                       DC_WIN_BUFFER_ADDR_MODE_LINEAR |
-                                       DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
-                                       DC_WIN_BUFFER_ADDR_MODE);
+               if (tegra_dc_feature_has_tiling(dc, win->idx)) {
+                       if (WIN_IS_TILED(win))
+                               tegra_dc_writel(dc,
+                                               DC_WIN_BUFFER_ADDR_MODE_TILE |
+                                               DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
+                                               DC_WIN_BUFFER_ADDR_MODE);
+                       else
+                               tegra_dc_writel(dc,
+                                               DC_WIN_BUFFER_ADDR_MODE_LINEAR |
+                                               DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
+                                               DC_WIN_BUFFER_ADDR_MODE);
+               }
 
                val = WIN_ENABLE;
                if (yuv)
@@ -2093,7 +2088,7 @@ u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc)
 {
        int crc = 0;
 
-       if(!dc) {
+       if (!dc) {
                dev_err(&dc->ndev->dev, "Failed to get dc.\n");
                goto crc_error;
        }
@@ -3030,6 +3025,8 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
        switch_dev_register(&dc->modeset_switch);
 #endif
 
+       tegra_dc_feature_register(dc);
+
        if (dc->pdata->default_out)
                tegra_dc_set_out(dc, dc->pdata->default_out);
        else
diff --git a/drivers/video/tegra/dc/dc_config.c b/drivers/video/tegra/dc/dc_config.c
new file mode 100644 (file)
index 0000000..3eebab6
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ * * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "dc_config.h"
+
+static struct tegra_dc_feature_entry t20_feature_entries_a[] = {
+       { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+       { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+       { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+       { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+       { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+       { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+       { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t20_feature_entries_b[] = {
+       { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+       { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+       { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+       { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+       { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+       { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+       { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t20_feature_table_a = {
+       ARRAY_SIZE(t20_feature_entries_a), t20_feature_entries_a,
+};
+
+struct tegra_dc_feature t20_feature_table_b = {
+       ARRAY_SIZE(t20_feature_entries_b), t20_feature_entries_b,
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_a[] = {
+       { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+       { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+       { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+       { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+       { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+       { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+       { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+static struct tegra_dc_feature_entry t30_feature_entries_b[] = {
+       { 0, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_A,} },
+       { 0, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 0, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 0, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 0,} },
+       { 0, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 0, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 1, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_B,} },
+       { 1, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 1, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 1, TEGRA_DC_FEATURE_FILTER_TYPE, {1, 1,} },
+       { 1, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 1, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+
+       { 2, TEGRA_DC_FEATURE_FORMATS, {TEGRA_WIN_FMT_WIN_C,} },
+       { 2, TEGRA_DC_FEATURE_BLEND_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SIZE, {4095, 16, 4095, 16,} },
+       { 2, TEGRA_DC_FEATURE_MAXIMUM_SCALE, {2, 2, 2, 2,} },
+       { 2, TEGRA_DC_FEATURE_FILTER_TYPE, {0, 1,} },
+       { 2, TEGRA_DC_FEATURE_LAYOUT_TYPE, {1,} },
+       { 2, TEGRA_DC_FEATURE_INVERT_TYPE, {1, 1, 0,} },
+};
+
+struct tegra_dc_feature t30_feature_table_a = {
+       ARRAY_SIZE(t30_feature_entries_a), t30_feature_entries_a,
+};
+
+struct tegra_dc_feature t30_feature_table_b = {
+       ARRAY_SIZE(t30_feature_entries_b), t30_feature_entries_b,
+};
+
+int tegra_dc_get_feature(struct tegra_dc_feature *feature, int win_idx,
+                                       enum tegra_dc_feature_option option)
+{
+       int i;
+       struct tegra_dc_feature_entry *entry;
+
+       if (!feature)
+               return -EINVAL;
+
+       for (i = 0; i < feature->num_entries; i++) {
+               entry = &feature->entries[i];
+               if (entry->window_index == win_idx && entry->option == option)
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation)
+{
+       int idx;
+       struct tegra_dc_feature_entry *entry;
+       enum tegra_dc_feature_option option;
+       struct tegra_dc_feature *feature = dc->feature;
+
+       switch (operation) {
+       case GET_WIN_FORMATS:
+               option = TEGRA_DC_FEATURE_FORMATS;
+               break;
+       case GET_WIN_SIZE:
+               option = TEGRA_DC_FEATURE_MAXIMUM_SIZE;
+               break;
+       case HAS_SCALE:
+               option = TEGRA_DC_FEATURE_MAXIMUM_SCALE;
+               break;
+       case HAS_TILED:
+               option = TEGRA_DC_FEATURE_LAYOUT_TYPE;
+               break;
+       case HAS_V_FILTER:
+               option = TEGRA_DC_FEATURE_FILTER_TYPE;
+               break;
+       case HAS_H_FILTER:
+               option = TEGRA_DC_FEATURE_FILTER_TYPE;
+               break;
+       case HAS_GEN2_BLEND:
+               option = TEGRA_DC_FEATURE_BLEND_TYPE;
+               break;
+       default:
+               return NULL;
+       }
+
+       idx = tegra_dc_get_feature(feature, win_idx, option);
+       if (IS_ERR_VALUE(idx))
+               return NULL;
+       entry = &feature->entries[idx];
+
+       return entry->arg;
+}
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx)
+{
+       int i;
+       long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_SCALE);
+
+       for (i = 0; i < ENTRY_SIZE; i++)
+               if (addr[i] != 1)
+                       return 1;
+       return 0;
+}
+
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx)
+{
+       long *addr = tegra_dc_parse_feature(dc, win_idx, HAS_TILED);
+
+       return addr[0];
+}
+
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation)
+{
+       long *addr = tegra_dc_parse_feature(dc, win_idx, operation);
+
+       if (operation == HAS_V_FILTER)
+               return addr[0];
+       else
+               return addr[1];
+}
+
+void tegra_dc_feature_register(struct tegra_dc *dc)
+{
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+       if (!dc->ndev->id)
+               dc->feature = &t20_feature_table_a;
+       else
+               dc->feature = &t20_feature_table_b;
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       if (!dc->ndev->id)
+               dc->feature = &t30_feature_table_a;
+       else
+               dc->feature = &t30_feature_table_b;
+#elif defined(CONFIG_ARCH_TEGRA_11x_SOC)
+       if (!dc->ndev->id)
+               dc->feature = &t114_feature_table_a;
+       else
+               dc->feature = &t114_feature_table_b;
+#elif defined(CONFIG_ARCH_TEGRA_14x_SOC)
+       if (!dc->ndev->id)
+               dc->feature = &t148_feature_table_a;
+       else
+               dc->feature = &t148_feature_table_b;
+#endif
+}
diff --git a/drivers/video/tegra/dc/dc_config.h b/drivers/video/tegra/dc/dc_config.h
new file mode 100644 (file)
index 0000000..a0670d1
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * drivers/video/tegra/dc/dc_config.c
+ * * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+#define __DRIVERS_VIDEO_TEGRA_DC_DC_CONFIG_H
+
+#include <linux/errno.h>
+#include <mach/dc.h>
+
+#include "dc_priv.h"
+
+#define ENTRY_SIZE     4       /* Size of feature entry args */
+
+/* These macros are defined based on T20/T30 formats. */
+#define TEGRA_WIN_FMT_BASE_CNT (TEGRA_WIN_FMT_YUV422RA + 1)
+#define TEGRA_WIN_FMT_BASE     ((1 << TEGRA_WIN_FMT_P8) | \
+                               (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+                               (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+                               (1 << TEGRA_WIN_FMT_B5G6R5) | \
+                               (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+                               (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+                               (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+                               (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+                               (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8) | \
+                               (1 << TEGRA_WIN_FMT_YCbCr422) | \
+                               (1 << TEGRA_WIN_FMT_YUV422) | \
+                               (1 << TEGRA_WIN_FMT_YCbCr420P) | \
+                               (1 << TEGRA_WIN_FMT_YUV420P) | \
+                               (1 << TEGRA_WIN_FMT_YCbCr422P) | \
+                               (1 << TEGRA_WIN_FMT_YUV422P) | \
+                               (1 << TEGRA_WIN_FMT_YCbCr422R) | \
+                               (1 << TEGRA_WIN_FMT_YUV422R) | \
+                               (1 << TEGRA_WIN_FMT_YCbCr422RA) | \
+                               (1 << TEGRA_WIN_FMT_YUV422RA))
+
+#define TEGRA_WIN_FMT_WIN_A    ((1 << TEGRA_WIN_FMT_P1) | \
+                               (1 << TEGRA_WIN_FMT_P2) | \
+                               (1 << TEGRA_WIN_FMT_P4) | \
+                               (1 << TEGRA_WIN_FMT_P8) | \
+                               (1 << TEGRA_WIN_FMT_B4G4R4A4) | \
+                               (1 << TEGRA_WIN_FMT_B5G5R5A) | \
+                               (1 << TEGRA_WIN_FMT_B5G6R5) | \
+                               (1 << TEGRA_WIN_FMT_AB5G5R5) | \
+                               (1 << TEGRA_WIN_FMT_B8G8R8A8) | \
+                               (1 << TEGRA_WIN_FMT_R8G8B8A8) | \
+                               (1 << TEGRA_WIN_FMT_B6x2G6x2R6x2A8) | \
+                               (1 << TEGRA_WIN_FMT_R6x2G6x2B6x2A8))
+
+#define TEGRA_WIN_FMT_WIN_B    (TEGRA_WIN_FMT_BASE & \
+                               ~(1 << TEGRA_WIN_FMT_B8G8R8A8) & \
+                               ~(1 << TEGRA_WIN_FMT_R8G8B8A8))
+
+#define TEGRA_WIN_FMT_WIN_C    TEGRA_WIN_FMT_BASE
+
+#define UNDEFINED      -1
+#define MAX_WIDTH      0
+#define MIN_WIDTH      1
+#define MAX_HEIGHT     2
+#define MIN_HEIGHT     3
+#define CHECK_SIZE(val, min, max)      ( \
+               ((val) < (min) || (val) > (max)) ? -EINVAL : 0)
+
+/* Available operations of feature table. */
+#define HAS_SCALE              1
+#define HAS_TILED              2
+#define HAS_V_FILTER           3
+#define HAS_H_FILTER           4
+#define HAS_GEN2_BLEND         5
+#define GET_WIN_FORMATS                6
+#define GET_WIN_SIZE           7
+
+enum tegra_dc_feature_option {
+       TEGRA_DC_FEATURE_FORMATS,
+       TEGRA_DC_FEATURE_BLEND_TYPE,
+       TEGRA_DC_FEATURE_MAXIMUM_SIZE,
+       TEGRA_DC_FEATURE_MAXIMUM_SCALE,
+       TEGRA_DC_FEATURE_FILTER_TYPE,
+       TEGRA_DC_FEATURE_LAYOUT_TYPE,
+       TEGRA_DC_FEATURE_INVERT_TYPE,
+};
+
+struct tegra_dc_feature_entry {
+       int window_index;
+       enum tegra_dc_feature_option option;
+       long arg[ENTRY_SIZE];
+};
+
+struct tegra_dc_feature {
+       unsigned num_entries;
+       struct tegra_dc_feature_entry *entries;
+};
+
+int tegra_dc_feature_has_scaling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_tiling(struct tegra_dc *dc, int win_idx);
+int tegra_dc_feature_has_filter(struct tegra_dc *dc, int win_idx, int operation);
+
+long *tegra_dc_parse_feature(struct tegra_dc *dc, int win_idx, int operation);
+void tegra_dc_feature_register(struct tegra_dc *dc);
+#endif
index 2f2dcec..49baa6b 100644 (file)
@@ -137,6 +137,8 @@ struct tegra_dc {
 
        struct tegra_dc_ext             *ext;
 
+       struct tegra_dc_feature         *feature;
+
 #ifdef CONFIG_DEBUG_FS
        struct dentry                   *debugdir;
 #endif
index 04553e7..66d8fea 100644 (file)
@@ -32,6 +32,7 @@
 
 /* XXX ew */
 #include "../dc_priv.h"
+#include "../dc_config.h"
 /* XXX ew 2 */
 #include "../../host/dev.h"
 /* XXX ew 3 */
@@ -172,10 +173,39 @@ void tegra_dc_ext_disable(struct tegra_dc_ext *ext)
        }
 }
 
+int tegra_dc_ext_check_windowattr(struct tegra_dc_ext *ext,
+                                               struct tegra_dc_win *win)
+{
+       long *addr;
+       struct tegra_dc *dc = ext->dc;
+
+       /* Check the window format */
+       addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_FORMATS);
+       if (!test_bit(win->fmt, addr)) {
+               dev_err(&dc->ndev->dev, "Color format of window %d is"
+                                               " invalid.\n", win->idx);
+               goto fail;
+       }
+
+       /* Check window size */
+       addr = tegra_dc_parse_feature(dc, win->idx, GET_WIN_SIZE);
+       if (CHECK_SIZE(win->out_w, addr[MIN_WIDTH], addr[MAX_WIDTH]) ||
+               CHECK_SIZE(win->out_h, addr[MIN_HEIGHT], addr[MAX_HEIGHT])) {
+               dev_err(&dc->ndev->dev, "Size of window %d is"
+                                               " invalid.\n", win->idx);
+               goto fail;
+       }
+
+       return 0;
+fail:
+       return -EINVAL;
+}
+
 static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
                               struct tegra_dc_win *win,
                               const struct tegra_dc_ext_flip_win *flip_win)
 {
+       int err = 0;
        struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
 
        if (flip_win->handle[TEGRA_DC_Y] == NULL) {
@@ -223,6 +253,11 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
        win->stride = flip_win->attr.stride;
        win->stride_uv = flip_win->attr.stride_uv;
 
+       err = tegra_dc_ext_check_windowattr(ext, win);
+       if (err < 0)
+               dev_err(&ext->dc->ndev->dev,
+                               "Window atrributes are invalid.\n");
+
        if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
                nvhost_syncpt_wait_timeout(
                                &nvhost_get_host(ext->dc->ndev)->syncpt,