From 6ef470d530c3ce43151b61de1b32d73d2a60b3a6 Mon Sep 17 00:00:00 2001 From: Kevin Huang Date: Mon, 7 May 2012 01:47:52 -0700 Subject: video: tegra: dc: Add display feature table support. 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 Reviewed-on: http://git-master/r/101078 Reviewed-by: Simone Willett Tested-by: Simone Willett --- drivers/video/tegra/dc/Makefile | 1 + drivers/video/tegra/dc/dc.c | 83 ++++++------ drivers/video/tegra/dc/dc_config.c | 252 +++++++++++++++++++++++++++++++++++++ drivers/video/tegra/dc/dc_config.h | 115 +++++++++++++++++ drivers/video/tegra/dc/dc_priv.h | 2 + drivers/video/tegra/dc/ext/dev.c | 35 ++++++ 6 files changed, 445 insertions(+), 43 deletions(-) create mode 100644 drivers/video/tegra/dc/dc_config.c create mode 100644 drivers/video/tegra/dc/dc_config.h (limited to 'drivers') 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 #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 +#include + +#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, -- cgit v1.2.3