video: tegra: dc: force the use of new bandwidth
[linux-3.10.git] / drivers / video / tegra / dc / bandwidth.c
1 /*
2  * drivers/video/tegra/dc/bandwidth.c
3  *
4  * Copyright (C) 2010-2012 NVIDIA Corporation
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19
20 #include <mach/clk.h>
21 #include <mach/dc.h>
22 #include <mach/fb.h>
23 #include <mach/mc.h>
24 #include <linux/nvhost.h>
25 #include <mach/latency_allowance.h>
26
27 #include "dc_reg.h"
28 #include "dc_config.h"
29 #include "dc_priv.h"
30
31 static int use_dynamic_emc = 1;
32
33 module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR);
34
35 /* uses the larger of w->bandwidth or w->new_bandwidth */
36 static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
37         struct tegra_dc_win *w)
38 {
39         /* windows A, B, C for first and second display */
40         static const enum tegra_la_id la_id_tab[2][3] = {
41                 /* first display */
42                 { TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B,
43                         TEGRA_LA_DISPLAY_0C },
44                 /* second display */
45                 { TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB,
46                         TEGRA_LA_DISPLAY_0CB },
47         };
48         /* window B V-filter tap for first and second display. */
49         static const enum tegra_la_id vfilter_tab[2] = {
50                 TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
51         };
52         unsigned long bw;
53
54         BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
55         BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab));
56         BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab));
57
58         bw = max(w->bandwidth, w->new_bandwidth);
59
60         /* tegra_dc_get_bandwidth() treats V filter windows as double
61          * bandwidth, but LA has a seperate client for V filter */
62         if (w->idx == 1 && win_use_v_filter(dc, w))
63                 bw /= 2;
64
65         /* our bandwidth is in kbytes/sec, but LA takes MBps.
66          * round up bandwidth to next 1MBps */
67         bw = bw / 1000 + 1;
68
69 #ifdef CONFIG_TEGRA_SILICON_PLATFORM
70         tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw);
71         /* if window B, also set the 1B client for the 2-tap V filter. */
72         if (w->idx == 1)
73                 tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw);
74 #endif
75 }
76
77 static unsigned int tegra_dc_windows_is_overlapped(struct tegra_dc_win *a,
78                                                    struct tegra_dc_win *b)
79 {
80         if (!WIN_IS_ENABLED(a) || !WIN_IS_ENABLED(b))
81                 return 0;
82
83         /* because memory access to load the fifo can overlap, only care
84          * if windows overlap vertically */
85         return ((a->out_y + a->out_h > b->out_y) && (a->out_y <= b->out_y)) ||
86                 ((b->out_y + b->out_h > a->out_y) && (b->out_y <= a->out_y));
87 }
88
89 static unsigned long tegra_dc_find_max_bandwidth(struct tegra_dc_win *wins[],
90                                                  int n)
91 {
92         unsigned i;
93         unsigned j;
94         unsigned overlap_count;
95         unsigned max_bw = 0;
96
97         WARN_ONCE(n > 3, "Code assumes at most 3 windows, bandwidth is likely"
98                          "inaccurate.\n");
99
100         /* If we had a large number of windows, we would compute adjacency
101          * graph representing 2 window overlaps, find all cliques in the graph,
102          * assign bandwidth to each clique, and then select the clique with
103          * maximum bandwidth. But because we have at most 3 windows,
104          * implementing proper Bron-Kerbosh algorithm would be an overkill,
105          * brute force will suffice.
106          *
107          * Thus: find maximum bandwidth for either single or a pair of windows
108          * and count number of window pair overlaps. If there are three
109          * pairs, all 3 window overlap.
110          */
111
112         overlap_count = 0;
113         for (i = 0; i < n; i++) {
114                 unsigned int bw1;
115
116                 if (wins[i] == NULL)
117                         continue;
118                 bw1 = wins[i]->new_bandwidth;
119                 if (bw1 > max_bw)
120                         /* Single window */
121                         max_bw = bw1;
122
123                 for (j = i + 1; j < n; j++) {
124                         if (wins[j] == NULL)
125                                 continue;
126                         if (tegra_dc_windows_is_overlapped(wins[i], wins[j])) {
127                                 unsigned int bw2 = wins[j]->new_bandwidth;
128                                 if (bw1 + bw2 > max_bw)
129                                         /* Window pair overlaps */
130                                         max_bw = bw1 + bw2;
131                                 overlap_count++;
132                         }
133                 }
134         }
135
136         if (overlap_count == 3)
137                 /* All three windows overlap */
138                 max_bw = wins[0]->new_bandwidth + wins[1]->new_bandwidth +
139                          wins[2]->new_bandwidth;
140
141         return max_bw;
142 }
143
144 /*
145  * Calculate peak EMC bandwidth for each enabled window =
146  * pixel_clock * win_bpp * (use_v_filter ? 2 : 1)) * H_scale_factor *
147  * (windows_tiling ? 2 : 1)
148  *
149  * note:
150  * (*) We use 2 tap V filter, so need double BW if use V filter
151  * (*) Tiling mode on T30 and DDR3 requires double BW
152  *
153  * return:
154  * bandwidth in kBps
155  */
156 static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
157         struct tegra_dc_win *w)
158 {
159         unsigned long ret;
160         int tiled_windows_bw_multiplier;
161         unsigned long bpp;
162
163         if (!WIN_IS_ENABLED(w))
164                 return 0;
165
166         if (dfixed_trunc(w->w) == 0 || dfixed_trunc(w->h) == 0 ||
167             w->out_w == 0 || w->out_h == 0)
168                 return 0;
169
170         tiled_windows_bw_multiplier =
171                 tegra_mc_get_tiled_memory_bandwidth_multiplier();
172
173         /* all of tegra's YUV formats(420 and 422) fetch 2 bytes per pixel,
174          * but the size reported by tegra_dc_fmt_bpp for the planar version
175          * is of the luma plane's size only. */
176         bpp = tegra_dc_is_yuv_planar(w->fmt) ?
177                 2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt);
178         ret = dc->mode.pclk / 1000UL * bpp / 8 * (
179                 win_use_v_filter(dc, w) ? 2 : 1) *
180                 dfixed_trunc(w->w) / w->out_w * (WIN_IS_TILED(w) ?
181                 tiled_windows_bw_multiplier : 1);
182
183         return ret;
184 }
185
186 static unsigned long tegra_dc_get_bandwidth(
187         struct tegra_dc_win *windows[], int n)
188 {
189         int i;
190
191         BUG_ON(n > DC_N_WINDOWS);
192
193         /* emc rate and latency allowance both need to know per window
194          * bandwidths */
195         for (i = 0; i < n; i++) {
196                 struct tegra_dc_win *w = windows[i];
197
198                 if (w)
199                         w->new_bandwidth =
200                                 tegra_dc_calc_win_bandwidth(w->dc, w);
201         }
202
203         return tegra_dc_find_max_bandwidth(windows, n);
204 }
205
206 /* to save power, call when display memory clients would be idle */
207 void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
208 {
209         trace_printk("%s:%s rate=%d\n", dc->ndev->name, __func__,
210                 dc->emc_clk_rate);
211         if (tegra_is_clk_enabled(dc->emc_clk))
212                 clk_disable(dc->emc_clk);
213         dc->emc_clk_rate = 0;
214 }
215
216 /* use the larger of dc->emc_clk_rate or dc->new_emc_clk_rate, and copies
217  * dc->new_emc_clk_rate into dc->emc_clk_rate.
218  * calling this function both before and after a flip is sufficient to select
219  * the best possible frequency and latency allowance.
220  * set use_new to true to force dc->new_emc_clk_rate programming.
221  */
222 void tegra_dc_program_bandwidth(struct tegra_dc *dc, bool use_new)
223 {
224         unsigned i;
225
226         if (use_new || dc->emc_clk_rate != dc->new_emc_clk_rate) {
227                 /* going from 0 to non-zero */
228                 if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk))
229                         clk_enable(dc->emc_clk);
230
231                 clk_set_rate(dc->emc_clk,
232                         max(dc->emc_clk_rate, dc->new_emc_clk_rate));
233                 dc->emc_clk_rate = dc->new_emc_clk_rate;
234
235                 /* going from non-zero to 0 */
236                 if (!dc->new_emc_clk_rate && tegra_is_clk_enabled(dc->emc_clk))
237                         clk_disable(dc->emc_clk);
238         }
239
240         for (i = 0; i < DC_N_WINDOWS; i++) {
241                 struct tegra_dc_win *w = &dc->windows[i];
242
243                 if ((use_new || w->bandwidth != w->new_bandwidth) &&
244                         w->new_bandwidth != 0)
245                         tegra_dc_set_latency_allowance(dc, w);
246                 w->bandwidth = w->new_bandwidth;
247                 trace_printk("%s:win%u bandwidth=%d\n", dc->ndev->name, w->idx,
248                         w->bandwidth);
249         }
250 }
251
252 int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
253 {
254         unsigned long new_rate;
255         struct tegra_dc *dc;
256
257         if (!use_dynamic_emc)
258                 return 0;
259
260         dc = windows[0]->dc;
261
262         /* calculate the new rate based on this POST */
263         new_rate = tegra_dc_get_bandwidth(windows, n);
264         if (WARN_ONCE(new_rate > (ULONG_MAX / 1000), "bandwidth maxed out\n"))
265                 new_rate = ULONG_MAX;
266         else
267                 new_rate = EMC_BW_TO_FREQ(new_rate * 1000);
268
269         if (tegra_dc_has_multiple_dc())
270                 new_rate = ULONG_MAX;
271
272         trace_printk("%s:new_emc_clk_rate=%ld\n", dc->ndev->name, new_rate);
273         dc->new_emc_clk_rate = new_rate;
274
275         return 0;
276 }