diff options
Diffstat (limited to 'arch/arm/mach-tegra/latency_allowance.c')
-rw-r--r-- | arch/arm/mach-tegra/latency_allowance.c | 598 |
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 | |||
103 | static struct dentry *latency_debug_dir; | ||
104 | |||
105 | struct 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 | |||
116 | static DEFINE_SPINLOCK(safety_lock); | ||
117 | |||
118 | static const int ns_per_tick = 30; | ||
119 | /* fifo atom size in bytes for non-fdc clients*/ | ||
120 | static const int normal_atom_size = 16; | ||
121 | /* fifo atom size in bytes for fdc clients*/ | ||
122 | static 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 | */ | ||
146 | struct 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 | |||
218 | struct 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 | |||
227 | struct 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 | |||
253 | struct 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 | |||
272 | struct 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 | |||
299 | static struct la_scaling_info scaling_info[TEGRA_LA_MAX_ID]; | ||
300 | static 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 | |||
321 | static 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 | |||
367 | static void set_disp_latency_thresholds(enum tegra_la_id id) | ||
368 | { | ||
369 | set_thresholds(&disp_info[id - ID(DISPLAY_0A)], id); | ||
370 | } | ||
371 | |||
372 | static 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 | */ | ||
380 | int 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 | */ | ||
438 | int 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); | ||
472 | exit: | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | void 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 | |||
501 | static 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 | |||
516 | static 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 | |||
521 | static 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 | |||
528 | static 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 | ®s_fops); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | late_initcall(tegra_latency_allowance_debugfs_init); | ||
542 | |||
543 | static 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 | |||
554 | core_initcall(tegra_latency_allowance_init); | ||
555 | |||
556 | #if TEST_LA_CODE | ||
557 | static 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 | |||
597 | late_initcall(test_la); | ||
598 | #endif | ||