summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/dc')
-rw-r--r--drivers/video/tegra/dc/Makefile1
-rw-r--r--drivers/video/tegra/dc/dc.c83
-rw-r--r--drivers/video/tegra/dc/dc_config.c252
-rw-r--r--drivers/video/tegra/dc/dc_config.h115
-rw-r--r--drivers/video/tegra/dc/dc_priv.h2
-rw-r--r--drivers/video/tegra/dc/ext/dev.c35
6 files changed, 445 insertions, 43 deletions
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
index 01f13918ca63..ebe9e890fad6 100644
--- a/drivers/video/tegra/dc/Makefile
+++ b/drivers/video/tegra/dc/Makefile
@@ -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/
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index c42df4c1957e..063d12e4714d 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -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
index 000000000000..3eebab6f66a8
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.c
@@ -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
index 000000000000..a0670d1d9f20
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_config.h
@@ -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
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 2f2dcec82055..49baa6b392d0 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -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
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index 04553e778390..66d8fea497cf 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -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,