aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/latency_allowance.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/latency_allowance.c')
-rw-r--r--arch/arm/mach-tegra/latency_allowance.c598
1 files changed, 598 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/latency_allowance.c b/arch/arm/mach-tegra/latency_allowance.c
new file mode 100644
index 00000000000..7698ba39f4c
--- /dev/null
+++ b/arch/arm/mach-tegra/latency_allowance.c
@@ -0,0 +1,598 @@
1/*
2 * arch/arm/mach-tegra/latency_allowance.c
3 *
4 * Copyright (C) 2011 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/types.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/debugfs.h>
21#include <linux/seq_file.h>
22#include <linux/err.h>
23#include <linux/spinlock_types.h>
24#include <linux/spinlock.h>
25#include <linux/stringify.h>
26#include <asm/bug.h>
27#include <asm/io.h>
28#include <asm/string.h>
29#include <mach/iomap.h>
30#include <mach/io.h>
31#include <mach/latency_allowance.h>
32
33#define MC_ARB_OVERRIDE 0xe8
34#define GLOBAL_LATENCY_SCALING_ENABLE_BIT 7
35
36#define MC_LA_AFI_0 0x2e0
37#define MC_LA_AVPC_ARM7_0 0x2e4
38#define MC_LA_DC_0 0x2e8
39#define MC_LA_DC_1 0x2ec
40#define MC_LA_DC_2 0x2f0
41#define MC_LA_DCB_0 0x2f4
42#define MC_LA_DCB_1 0x2f8
43#define MC_LA_DCB_2 0x2fc
44#define MC_LA_EPP_0 0x300
45#define MC_LA_EPP_1 0x304
46#define MC_LA_G2_0 0x308
47#define MC_LA_G2_1 0x30c
48#define MC_LA_HC_0 0x310
49#define MC_LA_HC_1 0x314
50#define MC_LA_HDA_0 0x318
51#define MC_LA_ISP_0 0x31C
52#define MC_LA_MPCORE_0 0x320
53#define MC_LA_MPCORELP_0 0x324
54#define MC_LA_MPE_0 0x328
55#define MC_LA_MPE_1 0x32c
56#define MC_LA_MPE_2 0x330
57#define MC_LA_NV_0 0x334
58#define MC_LA_NV_1 0x338
59#define MC_LA_NV2_0 0x33c
60#define MC_LA_NV2_1 0x340
61#define MC_LA_PPCS_0 0x344
62#define MC_LA_PPCS_1 0x348
63#define MC_LA_PTC_0 0x34c
64#define MC_LA_SATA_0 0x350
65#define MC_LA_VDE_0 0x354
66#define MC_LA_VDE_1 0x358
67#define MC_LA_VDE_2 0x35c
68#define MC_LA_VDE_3 0x360
69#define MC_LA_VI_0 0x364
70#define MC_LA_VI_1 0x368
71#define MC_LA_VI_2 0x36c
72
73#define DS_DISP_MCCIF_DISPLAY0A_HYST (0x481 * 4)
74#define DS_DISP_MCCIF_DISPLAY0B_HYST (0x482 * 4)
75#define DS_DISP_MCCIF_DISPLAY0C_HYST (0x483 * 4)
76#define DS_DISP_MCCIF_DISPLAY1B_HYST (0x484 * 4)
77
78#define DS_DISP_MCCIF_DISPLAY0AB_HYST (0x481 * 4)
79#define DS_DISP_MCCIF_DISPLAY0BB_HYST (0x482 * 4)
80#define DS_DISP_MCCIF_DISPLAY0CB_HYST (0x483 * 4)
81#define DS_DISP_MCCIF_DISPLAY1BB_HYST (0x484 * 4)
82
83#define VI_MCCIF_VIWSB_HYST (0x9a * 4)
84#define VI_MCCIF_VIWU_HYST (0x9b * 4)
85#define VI_MCCIF_VIWV_HYST (0x9c * 4)
86#define VI_MCCIF_VIWY_HYST (0x9d * 4)
87
88#define VI_TIMEOUT_WOCAL_VI (0x70 * 4)
89#define VI_RESERVE_3 (0x97 * 4)
90#define VI_RESERVE_4 (0x98 * 4)
91
92/* maximum valid value for latency allowance */
93#define MC_LA_MAX_VALUE 255
94
95#define ENABLE_LA_DEBUG 0
96#define TEST_LA_CODE 0
97
98#define la_debug(fmt, ...) \
99 if (ENABLE_LA_DEBUG) { \
100 printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__); \
101 }
102
103static struct dentry *latency_debug_dir;
104
105struct la_client_info {
106 unsigned int fifo_size_in_atoms;
107 unsigned int expiration_in_ns; /* worst case expiration value */
108 unsigned long reg_addr;
109 unsigned long mask;
110 unsigned long shift;
111 enum tegra_la_id id;
112 char *name;
113 bool scaling_supported;
114};
115
116static DEFINE_SPINLOCK(safety_lock);
117
118static const int ns_per_tick = 30;
119/* fifo atom size in bytes for non-fdc clients*/
120static const int normal_atom_size = 16;
121/* fifo atom size in bytes for fdc clients*/
122static const int fdc_atom_size = 32;
123
124#define MC_RA(r) \
125 ((u32)IO_ADDRESS(TEGRA_MC_BASE) + (MC_##r))
126#define RA(r) \
127 ((u32)IO_ADDRESS(TEGRA_MC_BASE) + (MC_LA_##r))
128
129#define MASK(x) \
130 ((0xFFFFFFFFUL >> (31 - (1 ? x) + (0 ? x))) << (0 ? x))
131#define SHIFT(x) \
132 (0 ? x)
133#define ID(id) \
134 TEGRA_LA_##id
135
136#define LA_INFO(f, e, a, r, id, ss) \
137{f, e, RA(a), MASK(r), SHIFT(r), ID(id), __stringify(id), ss}
138
139/*
140 * The rule for getting the fifo_size_in_atoms is:
141 * 1.If REORDER_DEPTH exists, use it(default is overridden).
142 * 2.Else if (write_client) use RFIFO_DEPTH.
143 * 3.Else (read client) use RDFIFO_DEPTH.
144 * Refer to project.h file.
145 */
146struct la_client_info la_info[] = {
147 LA_INFO(32, 150, AFI_0, 7 : 0, AFIR, false),
148 LA_INFO(32, 150, AFI_0, 23 : 16, AFIW, false),
149 LA_INFO(2, 150, AVPC_ARM7_0, 7 : 0, AVPC_ARM7R, false),
150 LA_INFO(2, 150, AVPC_ARM7_0, 23 : 16, AVPC_ARM7W, false),
151 LA_INFO(128, 1050, DC_0, 7 : 0, DISPLAY_0A, true),
152 LA_INFO(64, 1050, DC_0, 23 : 16, DISPLAY_0B, true),
153 LA_INFO(128, 1050, DC_1, 7 : 0, DISPLAY_0C, true),
154 LA_INFO(64, 1050, DC_1, 23 : 16, DISPLAY_1B, true),
155 LA_INFO(2, 1050, DC_2, 7 : 0, DISPLAY_HC, false),
156 LA_INFO(128, 1050, DCB_0, 7 : 0, DISPLAY_0AB, true),
157 LA_INFO(64, 1050, DCB_0, 23 : 16, DISPLAY_0BB, true),
158 LA_INFO(128, 1050, DCB_1, 7 : 0, DISPLAY_0CB, true),
159 LA_INFO(64, 1050, DCB_1, 23 : 16, DISPLAY_1BB, true),
160 LA_INFO(2, 1050, DCB_2, 7 : 0, DISPLAY_HCB, false),
161 LA_INFO(8, 150, EPP_0, 7 : 0, EPPUP, false),
162 LA_INFO(64, 150, EPP_0, 23 : 16, EPPU, false),
163 LA_INFO(64, 150, EPP_1, 7 : 0, EPPV, false),
164 LA_INFO(64, 150, EPP_1, 23 : 16, EPPY, false),
165 LA_INFO(64, 150, G2_0, 7 : 0, G2PR, false),
166 LA_INFO(64, 150, G2_0, 23 : 16, G2SR, false),
167 LA_INFO(48, 150, G2_1, 7 : 0, G2DR, false),
168 LA_INFO(128, 150, G2_1, 23 : 16, G2DW, false),
169 LA_INFO(16, 150, HC_0, 7 : 0, HOST1X_DMAR, false),
170 LA_INFO(8, 150, HC_0, 23 : 16, HOST1XR, false),
171 LA_INFO(32, 150, HC_1, 7 : 0, HOST1XW, false),
172 LA_INFO(16, 150, HDA_0, 7 : 0, HDAR, false),
173 LA_INFO(16, 150, HDA_0, 23 : 16, HDAW, false),
174 LA_INFO(64, 150, ISP_0, 7 : 0, ISPW, false),
175 LA_INFO(14, 150, MPCORE_0, 7 : 0, MPCORER, false),
176 LA_INFO(24, 150, MPCORE_0, 23 : 16, MPCOREW, false),
177 LA_INFO(14, 150, MPCORELP_0, 7 : 0, MPCORE_LPR, false),
178 LA_INFO(24, 150, MPCORELP_0, 23 : 16, MPCORE_LPW, false),
179 LA_INFO(8, 150, MPE_0, 7 : 0, MPE_UNIFBR, false),
180 LA_INFO(2, 150, MPE_0, 23 : 16, MPE_IPRED, false),
181 LA_INFO(64, 150, MPE_1, 7 : 0, MPE_AMEMRD, false),
182 LA_INFO(8, 150, MPE_1, 23 : 16, MPE_CSRD, false),
183 LA_INFO(8, 150, MPE_2, 7 : 0, MPE_UNIFBW, false),
184 LA_INFO(8, 150, MPE_2, 23 : 16, MPE_CSWR, false),
185 LA_INFO(48, 150, NV_0, 7 : 0, FDCDRD, false),
186 LA_INFO(64, 150, NV_0, 23 : 16, IDXSRD, false),
187 LA_INFO(64, 150, NV_1, 7 : 0, TEXSRD, false),
188 LA_INFO(48, 150, NV_1, 23 : 16, FDCDWR, false),
189 LA_INFO(48, 150, NV2_0, 7 : 0, FDCDRD2, false),
190 LA_INFO(64, 150, NV2_0, 23 : 16, IDXSRD2, false),
191 LA_INFO(64, 150, NV2_1, 7 : 0, TEXSRD2, false),
192 LA_INFO(48, 150, NV2_1, 23 : 16, FDCDWR2, false),
193 LA_INFO(2, 150, PPCS_0, 7 : 0, PPCS_AHBDMAR, false),
194 LA_INFO(8, 150, PPCS_0, 23 : 16, PPCS_AHBSLVR, false),
195 LA_INFO(2, 150, PPCS_1, 7 : 0, PPCS_AHBDMAW, false),
196 LA_INFO(4, 150, PPCS_1, 23 : 16, PPCS_AHBSLVW, false),
197 LA_INFO(2, 150, PTC_0, 7 : 0, PTCR, false),
198 LA_INFO(32, 150, SATA_0, 7 : 0, SATAR, false),
199 LA_INFO(32, 150, SATA_0, 23 : 16, SATAW, false),
200 LA_INFO(8, 150, VDE_0, 7 : 0, VDE_BSEVR, false),
201 LA_INFO(4, 150, VDE_0, 23 : 16, VDE_MBER, false),
202 LA_INFO(16, 150, VDE_1, 7 : 0, VDE_MCER, false),
203 LA_INFO(16, 150, VDE_1, 23 : 16, VDE_TPER, false),
204 LA_INFO(4, 150, VDE_2, 7 : 0, VDE_BSEVW, false),
205 LA_INFO(16, 150, VDE_2, 23 : 16, VDE_DBGW, false),
206 LA_INFO(2, 150, VDE_3, 7 : 0, VDE_MBEW, false),
207 LA_INFO(16, 150, VDE_3, 23 : 16, VDE_TPMW, false),
208 LA_INFO(8, 1050, VI_0, 7 : 0, VI_RUV, false),
209 LA_INFO(64, 1050, VI_0, 23 : 16, VI_WSB, true),
210 LA_INFO(64, 1050, VI_1, 7 : 0, VI_WU, true),
211 LA_INFO(64, 1050, VI_1, 23 : 16, VI_WV, true),
212 LA_INFO(64, 1050, VI_2, 7 : 0, VI_WY, true),
213
214/* end of list. */
215 LA_INFO(0, 0, AFI_0, 0 : 0, MAX_ID, false)
216};
217
218struct la_scaling_info {
219 unsigned int threshold_low;
220 unsigned int threshold_mid;
221 unsigned int threshold_high;
222 int scaling_ref_count;
223 int actual_la_to_set;
224 int la_set;
225};
226
227struct la_scaling_reg_info {
228 enum tegra_la_id id;
229 unsigned int tl_reg_addr;
230 unsigned int tl_mask;
231 unsigned int tl_shift;
232 unsigned int tm_reg_addr;
233 unsigned int tm_mask;
234 unsigned int tm_shift;
235 unsigned int th_reg_addr;
236 unsigned int th_mask;
237 unsigned int th_shift;
238};
239
240#define DISP1_RA(r) \
241 ((u32)IO_ADDRESS(TEGRA_DISPLAY_BASE) + DS_DISP_MCCIF_##r##_HYST)
242#define DISP2_RA(r) \
243 ((u32)IO_ADDRESS(TEGRA_DISPLAY2_BASE) + DS_DISP_MCCIF_##r##_HYST)
244
245#define DISP_SCALING_REG_INFO(id, r, ra) \
246 { \
247 ID(id), \
248 ra(r), MASK(15 : 8), SHIFT(15 : 8), \
249 ra(r), MASK(23 : 16), SHIFT(15 : 8), \
250 ra(r), MASK(7 : 0), SHIFT(15 : 8) \
251 }
252
253struct la_scaling_reg_info disp_info[] = {
254 DISP_SCALING_REG_INFO(DISPLAY_0A, DISPLAY0A, DISP1_RA),
255 DISP_SCALING_REG_INFO(DISPLAY_0B, DISPLAY0B, DISP1_RA),
256 DISP_SCALING_REG_INFO(DISPLAY_0C, DISPLAY0C, DISP1_RA),
257 DISP_SCALING_REG_INFO(DISPLAY_1B, DISPLAY1B, DISP1_RA),
258 DISP_SCALING_REG_INFO(MAX_ID, DISPLAY1B, DISP1_RA), /*dummy entry*/
259 DISP_SCALING_REG_INFO(DISPLAY_0AB, DISPLAY0AB, DISP2_RA),
260 DISP_SCALING_REG_INFO(DISPLAY_0BB, DISPLAY0BB, DISP2_RA),
261 DISP_SCALING_REG_INFO(DISPLAY_0CB, DISPLAY0CB, DISP2_RA),
262 DISP_SCALING_REG_INFO(DISPLAY_1BB, DISPLAY1BB, DISP2_RA),
263};
264
265#define VI_TH_RA(r) \
266 ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_MCCIF_##r##_HYST)
267#define VI_TM_RA(r) \
268 ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_TIMEOUT_WOCAL_VI)
269#define VI_TL_RA(r) \
270 ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_RESERVE_##r)
271
272struct la_scaling_reg_info vi_info[] = {
273 {
274 ID(VI_WSB),
275 VI_TL_RA(4), MASK(7 : 0), SHIFT(7 : 0),
276 VI_TM_RA(0), MASK(7 : 0), SHIFT(7 : 0),
277 VI_TH_RA(VIWSB), MASK(7 : 0), SHIFT(7 : 0)
278 },
279 {
280 ID(VI_WU),
281 VI_TL_RA(3), MASK(15 : 8), SHIFT(15 : 8),
282 VI_TM_RA(0), MASK(15 : 8), SHIFT(15 : 8),
283 VI_TH_RA(VIWU), MASK(7 : 0), SHIFT(7 : 0)
284 },
285 {
286 ID(VI_WV),
287 VI_TL_RA(3), MASK(7 : 0), SHIFT(7 : 0),
288 VI_TM_RA(0), MASK(23 : 16), SHIFT(23 : 16),
289 VI_TH_RA(VIWV), MASK(7 : 0), SHIFT(7 : 0)
290 },
291 {
292 ID(VI_WY),
293 VI_TL_RA(4), MASK(15 : 8), SHIFT(15 : 8),
294 VI_TM_RA(0), MASK(31 : 24), SHIFT(31 : 24),
295 VI_TH_RA(VIWY), MASK(7 : 0), SHIFT(7 : 0)
296 }
297};
298
299static struct la_scaling_info scaling_info[TEGRA_LA_MAX_ID];
300static int la_scaling_enable_count;
301
302#define VALIDATE_ID(id) \
303 do { \
304 if (id >= TEGRA_LA_MAX_ID) \
305 return -EINVAL; \
306 BUG_ON(la_info[id].id != id); \
307 } while (0)
308
309#define VALIDATE_BW(bw_in_mbps) \
310 do { \
311 if (bw_in_mbps >= 4096) \
312 return -EINVAL; \
313 } while (0)
314
315#define VALIDATE_THRESHOLDS(tl, tm, th) \
316 do { \
317 if (tl > 100 || tm > 100 || th > 100) \
318 return -EINVAL; \
319 } while (0)
320
321static void set_thresholds(struct la_scaling_reg_info *info,
322 enum tegra_la_id id)
323{
324 unsigned long reg_read;
325 unsigned long reg_write;
326 unsigned int thresh_low;
327 unsigned int thresh_mid;
328 unsigned int thresh_high;
329 int la_set;
330
331 reg_read = readl(la_info[id].reg_addr);
332 la_set = (reg_read & la_info[id].mask) >> la_info[id].shift;
333 /* la should be set before enabling scaling. */
334 BUG_ON(la_set != scaling_info[id].la_set);
335
336 thresh_low = (scaling_info[id].threshold_low * la_set) / 100;
337 thresh_mid = (scaling_info[id].threshold_mid * la_set) / 100;
338 thresh_high = (scaling_info[id].threshold_high * la_set) / 100;
339 la_debug("%s: la_set=%d, thresh_low=%d(%d%%), thresh_mid=%d(%d%%),"
340 " thresh_high=%d(%d%%) ", __func__, la_set,
341 thresh_low, scaling_info[id].threshold_low,
342 thresh_mid, scaling_info[id].threshold_mid,
343 thresh_high, scaling_info[id].threshold_high);
344
345 reg_read = readl(info->tl_reg_addr);
346 reg_write = (reg_read & ~info->tl_mask) |
347 (thresh_low << info->tl_shift);
348 writel(reg_write, info->tl_reg_addr);
349 la_debug("reg_addr=0x%x, read=0x%x, write=0x%x",
350 (u32)info->tl_reg_addr, (u32)reg_read, (u32)reg_write);
351
352 reg_read = readl(info->tm_reg_addr);
353 reg_write = (reg_read & ~info->tm_mask) |
354 (thresh_mid << info->tm_shift);
355 writel(reg_write, info->tm_reg_addr);
356 la_debug("reg_addr=0x%x, read=0x%x, write=0x%x",
357 (u32)info->tm_reg_addr, (u32)reg_read, (u32)reg_write);
358
359 reg_read = readl(info->th_reg_addr);
360 reg_write = (reg_read & ~info->th_mask) |
361 (thresh_high << info->th_shift);
362 writel(reg_write, info->th_reg_addr);
363 la_debug("reg_addr=0x%x, read=0x%x, write=0x%x",
364 (u32)info->th_reg_addr, (u32)reg_read, (u32)reg_write);
365}
366
367static void set_disp_latency_thresholds(enum tegra_la_id id)
368{
369 set_thresholds(&disp_info[id - ID(DISPLAY_0A)], id);
370}
371
372static void set_vi_latency_thresholds(enum tegra_la_id id)
373{
374 set_thresholds(&vi_info[id - ID(VI_WSB)], id);
375}
376
377/* Sets latency allowance based on clients memory bandwitdh requirement.
378 * Bandwidth passed is in mega bytes per second.
379 */
380int tegra_set_latency_allowance(enum tegra_la_id id,
381 unsigned int bandwidth_in_mbps)
382{
383 int ideal_la;
384 int la_to_set;
385 unsigned long reg_read;
386 unsigned long reg_write;
387 int bytes_per_atom = normal_atom_size;
388 struct la_client_info *ci;
389
390 VALIDATE_ID(id);
391 VALIDATE_BW(bandwidth_in_mbps);
392 if (id == ID(FDCDRD) || id == ID(FDCDWR) ||
393 id == ID(FDCDRD2) || id == ID(FDCDWR2))
394 bytes_per_atom = fdc_atom_size;
395
396 ci = &la_info[id];
397
398 if (bandwidth_in_mbps == 0) {
399 la_to_set = MC_LA_MAX_VALUE;
400 } else {
401 ideal_la = (ci->fifo_size_in_atoms * bytes_per_atom * 1000) /
402 (bandwidth_in_mbps * ns_per_tick);
403 la_to_set = ideal_la - (ci->expiration_in_ns/ns_per_tick) - 1;
404 }
405
406 la_debug("\n%s:id=%d,bw=%dmbps, la_to_set=%d",
407 __func__, id, bandwidth_in_mbps, la_to_set);
408 la_to_set = (la_to_set < 0) ? 0 : la_to_set;
409 la_to_set = (la_to_set > MC_LA_MAX_VALUE) ? MC_LA_MAX_VALUE : la_to_set;
410 scaling_info[id].actual_la_to_set = la_to_set;
411
412 /* until display can use latency allowance scaling, use a more
413 * aggressive LA setting. Bug 862709 */
414 if (id >= ID(DISPLAY_0A) && id <= ID(DISPLAY_HCB))
415 la_to_set /= 3;
416
417 spin_lock(&safety_lock);
418 reg_read = readl(ci->reg_addr);
419 reg_write = (reg_read & ~ci->mask) |
420 (la_to_set << ci->shift);
421 writel(reg_write, ci->reg_addr);
422 scaling_info[id].la_set = la_to_set;
423 la_debug("reg_addr=0x%x, read=0x%x, write=0x%x",
424 (u32)ci->reg_addr, (u32)reg_read, (u32)reg_write);
425 spin_unlock(&safety_lock);
426 return 0;
427}
428
429/* Thresholds for scaling are specified in % of fifo freeness.
430 * If threshold_low is specified as 20%, it means when the fifo free
431 * between 0 to 20%, use la as programmed_la.
432 * If threshold_mid is specified as 50%, it means when the fifo free
433 * between 20 to 50%, use la as programmed_la/2 .
434 * If threshold_high is specified as 80%, it means when the fifo free
435 * between 50 to 80%, use la as programmed_la/4.
436 * When the fifo is free between 80 to 100%, use la as 0(highest priority).
437 */
438int tegra_enable_latency_scaling(enum tegra_la_id id,
439 unsigned int threshold_low,
440 unsigned int threshold_mid,
441 unsigned int threshold_high)
442{
443 unsigned long reg;
444 unsigned long scaling_enable_reg = MC_RA(ARB_OVERRIDE);
445
446 VALIDATE_ID(id);
447 VALIDATE_THRESHOLDS(threshold_low, threshold_mid, threshold_high);
448
449 if (la_info[id].scaling_supported == false)
450 goto exit;
451
452 spin_lock(&safety_lock);
453
454 la_debug("\n%s: id=%d, tl=%d, tm=%d, th=%d", __func__,
455 id, threshold_low, threshold_mid, threshold_high);
456 scaling_info[id].threshold_low = threshold_low;
457 scaling_info[id].threshold_mid = threshold_mid;
458 scaling_info[id].threshold_high = threshold_high;
459 scaling_info[id].scaling_ref_count++;
460
461 if (id >= ID(DISPLAY_0A) && id <= ID(DISPLAY_1BB))
462 set_disp_latency_thresholds(id);
463 else if (id >= ID(VI_WSB) && id <= ID(VI_WY))
464 set_vi_latency_thresholds(id);
465 if (!la_scaling_enable_count++) {
466 reg = readl(scaling_enable_reg);
467 reg |= (1 << GLOBAL_LATENCY_SCALING_ENABLE_BIT);
468 writel(reg, scaling_enable_reg);
469 la_debug("enabled scaling.");
470 }
471 spin_unlock(&safety_lock);
472exit:
473 return 0;
474}
475
476void tegra_disable_latency_scaling(enum tegra_la_id id)
477{
478 unsigned long reg;
479 unsigned long scaling_enable_reg = MC_RA(ARB_OVERRIDE);
480
481 if (id >= TEGRA_LA_MAX_ID)
482 return;
483 BUG_ON(la_info[id].id != id);
484
485 if (la_info[id].scaling_supported == false)
486 return;
487 spin_lock(&safety_lock);
488 la_debug("\n%s: id=%d", __func__, id);
489 scaling_info[id].scaling_ref_count--;
490 BUG_ON(scaling_info[id].scaling_ref_count < 0);
491
492 if (!--la_scaling_enable_count) {
493 reg = readl(scaling_enable_reg);
494 reg = reg & ~(1 << GLOBAL_LATENCY_SCALING_ENABLE_BIT);
495 writel(reg, scaling_enable_reg);
496 la_debug("disabled scaling.");
497 }
498 spin_unlock(&safety_lock);
499}
500
501static int la_regs_show(struct seq_file *s, void *unused)
502{
503 unsigned i;
504 unsigned long la;
505
506 /* iterate the list, but don't print MAX_ID */
507 for (i = 0; i < ARRAY_SIZE(la_info) - 1; i++) {
508 la = (readl(la_info[i].reg_addr) & la_info[i].mask)
509 >> la_info[i].shift;
510 seq_printf(s, "%-16s: %4lu\n", la_info[i].name, la);
511 }
512
513 return 0;
514}
515
516static int dbg_la_regs_open(struct inode *inode, struct file *file)
517{
518 return single_open(file, la_regs_show, inode->i_private);
519}
520
521static const struct file_operations regs_fops = {
522 .open = dbg_la_regs_open,
523 .read = seq_read,
524 .llseek = seq_lseek,
525 .release = single_release,
526};
527
528static int __init tegra_latency_allowance_debugfs_init(void)
529{
530 if (latency_debug_dir)
531 return 0;
532
533 latency_debug_dir = debugfs_create_dir("tegra_latency", NULL);
534
535 debugfs_create_file("la_info", S_IRUGO, latency_debug_dir, NULL,
536 &regs_fops);
537
538 return 0;
539}
540
541late_initcall(tegra_latency_allowance_debugfs_init);
542
543static int __init tegra_latency_allowance_init(void)
544{
545 la_scaling_enable_count = 0;
546
547 tegra_set_latency_allowance(TEGRA_LA_G2PR, 20);
548 tegra_set_latency_allowance(TEGRA_LA_G2SR, 20);
549 tegra_set_latency_allowance(TEGRA_LA_G2DR, 20);
550 tegra_set_latency_allowance(TEGRA_LA_G2DW, 20);
551 return 0;
552}
553
554core_initcall(tegra_latency_allowance_init);
555
556#if TEST_LA_CODE
557static int __init test_la(void)
558{
559 int err;
560 enum tegra_la_id id = 0;
561 int repeat_count = 5;
562
563 do {
564 for (id = 0; id < TEGRA_LA_MAX_ID; id++) {
565 err = tegra_set_latency_allowance(id, 200);
566 if (err)
567 la_debug("\n***tegra_set_latency_allowance,"
568 " err=%d", err);
569 }
570
571 for (id = 0; id < TEGRA_LA_MAX_ID; id++) {
572 if (id >= ID(DISPLAY_0AB) && id <= ID(DISPLAY_HCB))
573 continue;
574 if (id >= ID(VI_WSB) && id <= ID(VI_WY))
575 continue;
576 err = tegra_enable_latency_scaling(id, 20, 50, 80);
577 if (err)
578 la_debug("\n***tegra_enable_latency_scaling,"
579 " err=%d", err);
580 }
581
582 la_debug("la_scaling_enable_count =%d",
583 la_scaling_enable_count);
584 for (id = 0; id < TEGRA_LA_MAX_ID; id++) {
585 if (id >= ID(DISPLAY_0AB) && id <= ID(DISPLAY_HCB))
586 continue;
587 if (id >= ID(VI_WSB) && id <= ID(VI_WY))
588 continue;
589 tegra_disable_latency_scaling(id);
590 }
591 la_debug("la_scaling_enable_count=%d",
592 la_scaling_enable_count);
593 } while (--repeat_count);
594 return 0;
595}
596
597late_initcall(test_la);
598#endif