summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/dc
diff options
context:
space:
mode:
authorJon Mayo <jmayo@nvidia.com>2012-06-01 11:56:04 -0700
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-06-06 06:41:51 -0700
commit333dd36a0c2f725abc41f2420420ec89538b9a04 (patch)
treee3342faf37320d1a6e4e8e27ec7bc07c1811a4a3 /drivers/video/tegra/dc
parentab96dd56b3e6bb1fb278cf42e81e7191cfb501b7 (diff)
video: tegra: dc: new file for bandwidth calc
Move bandwidth calculation logic into its own file. Change-Id: I57f58a6399805eede8783fea922c6f07dcbd54cb Signed-off-by: Jon Mayo <jmayo@nvidia.com> Reviewed-on: http://git-master/r/106291 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/video/tegra/dc')
-rw-r--r--drivers/video/tegra/dc/Makefile1
-rw-r--r--drivers/video/tegra/dc/bandwidth.c275
-rw-r--r--drivers/video/tegra/dc/dc.c334
-rw-r--r--drivers/video/tegra/dc/dc_config.h14
-rw-r--r--drivers/video/tegra/dc/dc_priv.h88
5 files changed, 382 insertions, 330 deletions
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
index ebe9e890fad6..8a826412f90c 100644
--- a/drivers/video/tegra/dc/Makefile
+++ b/drivers/video/tegra/dc/Makefile
@@ -1,4 +1,5 @@
GCOV_PROFILE := y
+obj-y += bandwidth.o
obj-y += dc.o
obj-y += rgb.o
obj-y += hdmi.o
diff --git a/drivers/video/tegra/dc/bandwidth.c b/drivers/video/tegra/dc/bandwidth.c
new file mode 100644
index 000000000000..a1da7ef0a995
--- /dev/null
+++ b/drivers/video/tegra/dc/bandwidth.c
@@ -0,0 +1,275 @@
+/*
+ * drivers/video/tegra/dc/bandwidth.c
+ *
+ * Copyright (C) 2010-2012 NVIDIA Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <mach/clk.h>
+#include <mach/dc.h>
+#include <mach/fb.h>
+#include <mach/mc.h>
+#include <linux/nvhost.h>
+#include <mach/latency_allowance.h>
+
+#include "dc_reg.h"
+#include "dc_config.h"
+#include "dc_priv.h"
+
+static int use_dynamic_emc = 1;
+
+module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR);
+
+/* uses the larger of w->bandwidth or w->new_bandwidth, and copies
+ * w->new_bandwidth into w->bandwidth */
+static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
+ struct tegra_dc_win *w)
+{
+ /* windows A, B, C for first and second display */
+ static const enum tegra_la_id la_id_tab[2][3] = {
+ /* first display */
+ { TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B,
+ TEGRA_LA_DISPLAY_0C },
+ /* second display */
+ { TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB,
+ TEGRA_LA_DISPLAY_0CB },
+ };
+ /* window B V-filter tap for first and second display. */
+ static const enum tegra_la_id vfilter_tab[2] = {
+ TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
+ };
+ unsigned long bw;
+
+ BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
+ BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab));
+ BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab));
+
+ bw = max(w->bandwidth, w->new_bandwidth);
+
+ /* 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(dc, w))
+ bw /= 2;
+
+ /* our bandwidth is in kbytes/sec, but LA takes MBps.
+ * round up bandwidth to next 1MBps */
+ bw = bw / 1000 + 1;
+
+#ifdef CONFIG_TEGRA_SILICON_PLATFORM
+ tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw);
+ /* if window B, also set the 1B client for the 2-tap V filter. */
+ if (w->idx == 1)
+ tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw);
+#endif
+
+ w->bandwidth = w->new_bandwidth;
+}
+
+static unsigned int tegra_dc_windows_is_overlapped(struct tegra_dc_win *a,
+ struct tegra_dc_win *b)
+{
+ if (!WIN_IS_ENABLED(a) || !WIN_IS_ENABLED(b))
+ return 0;
+
+ /* because memory access to load the fifo can overlap, only care
+ * if windows overlap vertically */
+ return ((a->out_y + a->out_h > b->out_y) && (a->out_y <= b->out_y)) ||
+ ((b->out_y + b->out_h > a->out_y) && (b->out_y <= a->out_y));
+}
+
+static unsigned long tegra_dc_find_max_bandwidth(struct tegra_dc_win *wins[],
+ int n)
+{
+ unsigned i;
+ unsigned j;
+ unsigned overlap_count;
+ unsigned max_bw = 0;
+
+ WARN_ONCE(n > 3, "Code assumes at most 3 windows, bandwidth is likely"
+ "inaccurate.\n");
+
+ /* If we had a large number of windows, we would compute adjacency
+ * graph representing 2 window overlaps, find all cliques in the graph,
+ * assign bandwidth to each clique, and then select the clique with
+ * maximum bandwidth. But because we have at most 3 windows,
+ * implementing proper Bron-Kerbosh algorithm would be an overkill,
+ * brute force will suffice.
+ *
+ * Thus: find maximum bandwidth for either single or a pair of windows
+ * and count number of window pair overlaps. If there are three
+ * pairs, all 3 window overlap.
+ */
+
+ overlap_count = 0;
+ for (i = 0; i < n; i++) {
+ unsigned int bw1;
+
+ if (wins[i] == NULL)
+ continue;
+ bw1 = wins[i]->new_bandwidth;
+ if (bw1 > max_bw)
+ /* Single window */
+ max_bw = bw1;
+
+ for (j = i + 1; j < n; j++) {
+ if (wins[j] == NULL)
+ continue;
+ if (tegra_dc_windows_is_overlapped(wins[i], wins[j])) {
+ unsigned int bw2 = wins[j]->new_bandwidth;
+ if (bw1 + bw2 > max_bw)
+ /* Window pair overlaps */
+ max_bw = bw1 + bw2;
+ overlap_count++;
+ }
+ }
+ }
+
+ if (overlap_count == 3)
+ /* All three windows overlap */
+ max_bw = wins[0]->new_bandwidth + wins[1]->new_bandwidth +
+ wins[2]->new_bandwidth;
+
+ return max_bw;
+}
+
+/*
+ * Calculate peak EMC bandwidth for each enabled window =
+ * pixel_clock * win_bpp * (use_v_filter ? 2 : 1)) * H_scale_factor *
+ * (windows_tiling ? 2 : 1)
+ *
+ * note:
+ * (*) We use 2 tap V filter, so need double BW if use V filter
+ * (*) Tiling mode on T30 and DDR3 requires double BW
+ *
+ * return:
+ * bandwidth in kBps
+ */
+static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
+ struct tegra_dc_win *w)
+{
+ unsigned long ret;
+ int tiled_windows_bw_multiplier;
+ unsigned long bpp;
+
+ if (!WIN_IS_ENABLED(w))
+ return 0;
+
+ if (dfixed_trunc(w->w) == 0 || dfixed_trunc(w->h) == 0 ||
+ w->out_w == 0 || w->out_h == 0)
+ return 0;
+
+ tiled_windows_bw_multiplier =
+ tegra_mc_get_tiled_memory_bandwidth_multiplier();
+
+ /* all of tegra's YUV formats(420 and 422) fetch 2 bytes per pixel,
+ * but the size reported by tegra_dc_fmt_bpp for the planar version
+ * 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(dc, w) ? 2 : 1) *
+ dfixed_trunc(w->w) / w->out_w * (WIN_IS_TILED(w) ?
+ tiled_windows_bw_multiplier : 1);
+
+ return ret;
+}
+
+static unsigned long tegra_dc_get_bandwidth(
+ struct tegra_dc_win *windows[], int n)
+{
+ int i;
+
+ BUG_ON(n > DC_N_WINDOWS);
+
+ /* emc rate and latency allowance both need to know per window
+ * bandwidths */
+ for (i = 0; i < n; i++) {
+ struct tegra_dc_win *w = windows[i];
+
+ if (w)
+ w->new_bandwidth =
+ tegra_dc_calc_win_bandwidth(w->dc, w);
+ }
+
+ return tegra_dc_find_max_bandwidth(windows, n);
+}
+
+/* to save power, call when display memory clients would be idle */
+void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
+{
+ trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__,
+ dc->emc_clk_rate);
+ if (tegra_is_clk_enabled(dc->emc_clk))
+ clk_disable(dc->emc_clk);
+ dc->emc_clk_rate = 0;
+}
+
+/* use the larger of dc->emc_clk_rate or dc->new_emc_clk_rate, and copies
+ * dc->new_emc_clk_rate into dc->emc_clk_rate.
+ * calling this function both before and after a flip is sufficient to select
+ * the best possible frequency and latency allowance.
+ */
+void tegra_dc_program_bandwidth(struct tegra_dc *dc)
+{
+ unsigned i;
+
+ if (dc->emc_clk_rate != dc->new_emc_clk_rate) {
+ /* going from 0 to non-zero */
+ if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk))
+ clk_enable(dc->emc_clk);
+
+ clk_set_rate(dc->emc_clk,
+ max(dc->emc_clk_rate, dc->new_emc_clk_rate));
+ dc->emc_clk_rate = dc->new_emc_clk_rate;
+
+ if (!dc->new_emc_clk_rate) /* going from non-zero to 0 */
+ clk_disable(dc->emc_clk);
+ }
+
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *w = &dc->windows[i];
+
+ if (w->bandwidth != w->new_bandwidth && w->new_bandwidth != 0)
+ tegra_dc_set_latency_allowance(dc, w);
+ trace_printk("%s:win%u bandwidth=%d\n", dc->ndev->name, w->idx,
+ w->bandwidth);
+ }
+}
+
+int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
+{
+ unsigned long new_rate;
+ struct tegra_dc *dc;
+
+ if (!use_dynamic_emc)
+ return 0;
+
+ dc = windows[0]->dc;
+
+ /* calculate the new rate based on this POST */
+ new_rate = tegra_dc_get_bandwidth(windows, n);
+ if (WARN_ONCE(new_rate > (ULONG_MAX / 1000), "bandwidth maxed out\n"))
+ new_rate = ULONG_MAX;
+ else
+ new_rate = EMC_BW_TO_FREQ(new_rate * 1000);
+
+ if (tegra_dc_has_multiple_dc())
+ new_rate = ULONG_MAX;
+
+ trace_printk("%s:new_emc_clk_rate=%ld\n", dc->ndev->name, new_rate);
+ dc->new_emc_clk_rate = new_rate;
+
+ return 0;
+}
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index e8b650cb4de7..256cacf7ec62 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -85,106 +85,11 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc);
module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
-static int use_dynamic_emc = 1;
-
-module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR);
-
struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
DEFINE_MUTEX(shared_lock);
-static inline bool win_use_v_filter(struct tegra_dc *dc, const struct tegra_dc_win *win)
-{
- 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(struct tegra_dc *dc, const struct tegra_dc_win *win)
-{
- return tegra_dc_feature_has_filter(dc, win->idx, HAS_H_FILTER) &&
- win->w.full != dfixed_const(win->out_w);
-}
-
-static inline int tegra_dc_fmt_bpp(int fmt)
-{
- switch (fmt) {
- case TEGRA_WIN_FMT_P1:
- return 1;
-
- case TEGRA_WIN_FMT_P2:
- return 2;
-
- case TEGRA_WIN_FMT_P4:
- return 4;
-
- case TEGRA_WIN_FMT_P8:
- return 8;
-
- case TEGRA_WIN_FMT_B4G4R4A4:
- case TEGRA_WIN_FMT_B5G5R5A:
- case TEGRA_WIN_FMT_B5G6R5:
- case TEGRA_WIN_FMT_AB5G5R5:
- return 16;
-
- case TEGRA_WIN_FMT_B8G8R8A8:
- case TEGRA_WIN_FMT_R8G8B8A8:
- case TEGRA_WIN_FMT_B6x2G6x2R6x2A8:
- case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
- return 32;
-
- /* for planar formats, size of the Y plane, 8bit */
- case TEGRA_WIN_FMT_YCbCr420P:
- case TEGRA_WIN_FMT_YUV420P:
- case TEGRA_WIN_FMT_YCbCr422P:
- case TEGRA_WIN_FMT_YUV422P:
- case TEGRA_WIN_FMT_YCbCr422R:
- case TEGRA_WIN_FMT_YUV422R:
- case TEGRA_WIN_FMT_YCbCr422RA:
- case TEGRA_WIN_FMT_YUV422RA:
- return 8;
-
- /* YUYV packed into 32-bits */
- case TEGRA_WIN_FMT_YCbCr422:
- case TEGRA_WIN_FMT_YUV422:
- return 16;
- }
- return 0;
-}
-
-static inline bool tegra_dc_is_yuv(int fmt)
-{
- switch (fmt) {
- case TEGRA_WIN_FMT_YUV420P:
- case TEGRA_WIN_FMT_YCbCr420P:
- case TEGRA_WIN_FMT_YCbCr422P:
- case TEGRA_WIN_FMT_YUV422P:
- case TEGRA_WIN_FMT_YCbCr422:
- case TEGRA_WIN_FMT_YUV422:
- case TEGRA_WIN_FMT_YCbCr422R:
- case TEGRA_WIN_FMT_YUV422R:
- case TEGRA_WIN_FMT_YCbCr422RA:
- case TEGRA_WIN_FMT_YUV422RA:
- return true;
- }
- return false;
-}
-
-static inline bool tegra_dc_is_yuv_planar(int fmt)
-{
- switch (fmt) {
- case TEGRA_WIN_FMT_YUV420P:
- case TEGRA_WIN_FMT_YCbCr420P:
- case TEGRA_WIN_FMT_YCbCr422P:
- case TEGRA_WIN_FMT_YUV422P:
- case TEGRA_WIN_FMT_YCbCr422R:
- case TEGRA_WIN_FMT_YUV422R:
- case TEGRA_WIN_FMT_YCbCr422RA:
- case TEGRA_WIN_FMT_YUV422RA:
- return true;
- }
- return false;
-}
-
#define DUMP_REG(a) do { \
snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
#a, a, tegra_dc_readl(dc, a)); \
@@ -569,7 +474,7 @@ out:
return ret;
}
-static unsigned int tegra_dc_has_multiple_dc(void)
+unsigned int tegra_dc_has_multiple_dc(void)
{
unsigned int idx;
unsigned int cnt = 0;
@@ -882,239 +787,6 @@ static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
}
}
-static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
- struct tegra_dc_win *w)
-{
- /* windows A, B, C for first and second display */
- static const enum tegra_la_id la_id_tab[2][3] = {
- /* first display */
- { TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B,
- TEGRA_LA_DISPLAY_0C },
- /* second display */
- { TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB,
- TEGRA_LA_DISPLAY_0CB },
- };
- /* window B V-filter tap for first and second display. */
- static const enum tegra_la_id vfilter_tab[2] = {
- TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
- };
- unsigned long bw;
-
- BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
- BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab));
- BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab));
-
- bw = w->new_bandwidth;
-
- /* 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(dc, w))
- bw /= 2;
-
- /* our bandwidth is in kbytes/sec, but LA takes MBps.
- * round up bandwidth to next 1MBps */
- bw = bw / 1000 + 1;
-
-#ifdef CONFIG_TEGRA_SILICON_PLATFORM
- tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw);
- /* if window B, also set the 1B client for the 2-tap V filter. */
- if (w->idx == 1)
- tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw);
-#endif
-
- w->bandwidth = w->new_bandwidth;
-}
-
-static unsigned int tegra_dc_windows_is_overlapped(struct tegra_dc_win *a,
- struct tegra_dc_win *b)
-{
- if (!WIN_IS_ENABLED(a) || !WIN_IS_ENABLED(b))
- return 0;
-
- /* because memory access to load the fifo can overlap, only care
- * if windows overlap vertically */
- return ((a->out_y + a->out_h > b->out_y) && (a->out_y <= b->out_y)) ||
- ((b->out_y + b->out_h > a->out_y) && (b->out_y <= a->out_y));
-}
-
-static unsigned long tegra_dc_find_max_bandwidth(struct tegra_dc_win *wins[],
- int n)
-{
- unsigned i;
- unsigned j;
- unsigned overlap_count;
- unsigned max_bw = 0;
-
- WARN_ONCE(n > 3, "Code assumes at most 3 windows, bandwidth is likely"
- "inaccurate.\n");
-
- /* If we had a large number of windows, we would compute adjacency
- * graph representing 2 window overlaps, find all cliques in the graph,
- * assign bandwidth to each clique, and then select the clique with
- * maximum bandwidth. But because we have at most 3 windows,
- * implementing proper Bron-Kerbosh algorithm would be an overkill,
- * brute force will suffice.
- *
- * Thus: find maximum bandwidth for either single or a pair of windows
- * and count number of window pair overlaps. If there are three
- * pairs, all 3 window overlap.
- */
-
- overlap_count = 0;
- for (i = 0; i < n; i++) {
- unsigned int bw1;
-
- if (wins[i] == NULL)
- continue;
- bw1 = wins[i]->new_bandwidth;
- if (bw1 > max_bw)
- /* Single window */
- max_bw = bw1;
-
- for (j = i + 1; j < n; j++) {
- if (wins[j] == NULL)
- continue;
- if (tegra_dc_windows_is_overlapped(wins[i], wins[j])) {
- unsigned int bw2 = wins[j]->new_bandwidth;
- if (bw1 + bw2 > max_bw)
- /* Window pair overlaps */
- max_bw = bw1 + bw2;
- overlap_count++;
- }
- }
- }
-
- if (overlap_count == 3)
- /* All three windows overlap */
- max_bw = wins[0]->new_bandwidth + wins[1]->new_bandwidth +
- wins[2]->new_bandwidth;
-
- return max_bw;
-}
-
-/*
- * Calculate peak EMC bandwidth for each enabled window =
- * pixel_clock * win_bpp * (use_v_filter ? 2 : 1)) * H_scale_factor *
- * (windows_tiling ? 2 : 1)
- *
- * note:
- * (*) We use 2 tap V filter, so need double BW if use V filter
- * (*) Tiling mode on T30 and DDR3 requires double BW
- *
- * return:
- * bandwidth in kBps
- */
-static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
- struct tegra_dc_win *w)
-{
- unsigned long ret;
- int tiled_windows_bw_multiplier;
- unsigned long bpp;
-
- if (!WIN_IS_ENABLED(w))
- return 0;
-
- if (dfixed_trunc(w->w) == 0 || dfixed_trunc(w->h) == 0 ||
- w->out_w == 0 || w->out_h == 0)
- return 0;
-
- tiled_windows_bw_multiplier =
- tegra_mc_get_tiled_memory_bandwidth_multiplier();
-
- /* all of tegra's YUV formats(420 and 422) fetch 2 bytes per pixel,
- * but the size reported by tegra_dc_fmt_bpp for the planar version
- * 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(dc, w) ? 2 : 1)
- * dfixed_trunc(w->w) / w->out_w *
- (WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1);
-
- return ret;
-}
-
-static unsigned long tegra_dc_get_bandwidth(
- struct tegra_dc_win *windows[], int n)
-{
- int i;
-
- BUG_ON(n > DC_N_WINDOWS);
-
- /* emc rate and latency allowance both need to know per window
- * bandwidths */
- for (i = 0; i < n; i++) {
- struct tegra_dc_win *w = windows[i];
-
- if (w)
- w->new_bandwidth =
- tegra_dc_calc_win_bandwidth(w->dc, w);
- }
-
- return tegra_dc_find_max_bandwidth(windows, n);
-}
-
-/* to save power, call when display memory clients would be idle */
-static void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
-{
- trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__,
- dc->emc_clk_rate);
- if (tegra_is_clk_enabled(dc->emc_clk))
- clk_disable(dc->emc_clk);
- dc->emc_clk_rate = 0;
-}
-
-static void tegra_dc_program_bandwidth(struct tegra_dc *dc)
-{
- unsigned i;
-
- if (dc->emc_clk_rate != dc->new_emc_clk_rate) {
- /* going from 0 to non-zero */
- if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk))
- clk_enable(dc->emc_clk);
-
- dc->emc_clk_rate = dc->new_emc_clk_rate;
- clk_set_rate(dc->emc_clk, dc->emc_clk_rate);
-
- if (!dc->new_emc_clk_rate) /* going from non-zero to 0 */
- clk_disable(dc->emc_clk);
- }
-
- for (i = 0; i < DC_N_WINDOWS; i++) {
- struct tegra_dc_win *w = &dc->windows[i];
-
- if (w->bandwidth != w->new_bandwidth && w->new_bandwidth != 0)
- tegra_dc_set_latency_allowance(dc, w);
- trace_printk("%s:win%u bandwidth=%d\n", dc->ndev->name, w->idx,
- w->bandwidth);
- }
-}
-
-static int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
-{
- unsigned long new_rate;
- struct tegra_dc *dc;
-
- if (!use_dynamic_emc)
- return 0;
-
- dc = windows[0]->dc;
-
- /* calculate the new rate based on this POST */
- new_rate = tegra_dc_get_bandwidth(windows, n);
- if (WARN_ONCE(new_rate > (ULONG_MAX / 1000), "bandwidth maxed out\n"))
- new_rate = ULONG_MAX;
- else
- new_rate = EMC_BW_TO_FREQ(new_rate * 1000);
-
- if (tegra_dc_has_multiple_dc())
- new_rate = ULONG_MAX;
-
- trace_printk("%s:new_emc_clk_rate=%ld\n", dc->ndev->name, new_rate);
- dc->new_emc_clk_rate = new_rate;
-
- return 0;
-}
-
static inline u32 compute_dda_inc(fixed20_12 in, unsigned out_int,
bool v, unsigned Bpp)
{
@@ -2127,6 +1799,10 @@ static void tegra_dc_vblank(struct work_struct *work)
bool nvsd_updated = false;
mutex_lock(&dc->lock);
+ /* use the new frame's bandwidth setting instead of max(current, new),
+ * skip this if we're using tegra_dc_one_shot_worker() */
+ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE))
+ tegra_dc_program_bandwidth(dc);
/* Update the SD brightness */
if (dc->enabled && dc->out->sd_settings)
diff --git a/drivers/video/tegra/dc/dc_config.h b/drivers/video/tegra/dc/dc_config.h
index 314cd11e77f9..4cc924184275 100644
--- a/drivers/video/tegra/dc/dc_config.h
+++ b/drivers/video/tegra/dc/dc_config.h
@@ -145,4 +145,18 @@ 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);
+
+static inline bool win_use_v_filter(struct tegra_dc *dc,
+ const struct tegra_dc_win *win)
+{
+ 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(struct tegra_dc *dc,
+ const struct tegra_dc_win *win)
+{
+ return tegra_dc_feature_has_filter(dc, win->idx, HAS_H_FILTER) &&
+ win->w.full != dfixed_const(win->out_w);
+}
+
#endif
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index ce7ac3c7b0d0..4f53f60f2599 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -205,6 +205,86 @@ static inline unsigned long tegra_dc_get_default_emc_clk_rate(
return dc->pdata->emc_clk_rate ? dc->pdata->emc_clk_rate : ULONG_MAX;
}
+static inline int tegra_dc_fmt_bpp(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_P1:
+ return 1;
+
+ case TEGRA_WIN_FMT_P2:
+ return 2;
+
+ case TEGRA_WIN_FMT_P4:
+ return 4;
+
+ case TEGRA_WIN_FMT_P8:
+ return 8;
+
+ case TEGRA_WIN_FMT_B4G4R4A4:
+ case TEGRA_WIN_FMT_B5G5R5A:
+ case TEGRA_WIN_FMT_B5G6R5:
+ case TEGRA_WIN_FMT_AB5G5R5:
+ return 16;
+
+ case TEGRA_WIN_FMT_B8G8R8A8:
+ case TEGRA_WIN_FMT_R8G8B8A8:
+ case TEGRA_WIN_FMT_B6x2G6x2R6x2A8:
+ case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
+ return 32;
+
+ /* for planar formats, size of the Y plane, 8bit */
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return 8;
+
+ /* YUYV packed into 32-bits */
+ case TEGRA_WIN_FMT_YCbCr422:
+ case TEGRA_WIN_FMT_YUV422:
+ return 16;
+ }
+ return 0;
+}
+
+static inline bool tegra_dc_is_yuv(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422:
+ case TEGRA_WIN_FMT_YUV422:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return true;
+ }
+ return false;
+}
+
+static inline bool tegra_dc_is_yuv_planar(int fmt)
+{
+ switch (fmt) {
+ case TEGRA_WIN_FMT_YUV420P:
+ case TEGRA_WIN_FMT_YCbCr420P:
+ case TEGRA_WIN_FMT_YCbCr422P:
+ case TEGRA_WIN_FMT_YUV422P:
+ case TEGRA_WIN_FMT_YCbCr422R:
+ case TEGRA_WIN_FMT_YUV422R:
+ case TEGRA_WIN_FMT_YCbCr422RA:
+ case TEGRA_WIN_FMT_YUV422RA:
+ return true;
+ }
+ return false;
+}
+
void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk);
extern struct tegra_dc_out_ops tegra_dc_rgb_ops;
@@ -227,5 +307,11 @@ void tegra_dc_disable_crc(struct tegra_dc *dc);
void tegra_dc_set_out_pin_polars(struct tegra_dc *dc,
const struct tegra_dc_out_pin *pins,
const unsigned int n_pins);
-#endif
+/* defined in dc.c, used in bandwidth.c */
+unsigned int tegra_dc_has_multiple_dc(void);
+/* defined in bandwidth.c, used in dc.c */
+void tegra_dc_clear_bandwidth(struct tegra_dc *dc);
+void tegra_dc_program_bandwidth(struct tegra_dc *dc);
+int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n);
+#endif