aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-12-26 13:57:50 -0500
committerOlof Johansson <olof@lixom.net>2013-12-26 13:57:50 -0500
commit92fa35e93074d025a9fd6b1b65cd00b83beef268 (patch)
treed43e434ab86473ed99f430ef2678e088db7c9b5d
parent34edea7adc4bdf7abe724de552883dfcf39fca61 (diff)
parent9d4450ae87398e248e8700e3507748e0d1751e25 (diff)
Merge tag 'tegra-for-3.14-powergate' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/soc
From Stephen Warren: ARM: tegra: powergate driver changes This branch includes all the changes to Tegra's powergate driver for 3.14. These are separate out, since the Tegra DRM changes for 3.14 rely on the new APIs introduced here. A few cleanups and fixes are included, plus additions of Tegra124 SoC support, and a new API for manipulating Tegra's IO rail deep power down states. This branch is based on tag tegra-for-3.14-dmas-resets-rework, in order to avoid conflicts with the addition of common reset controller support to the powergate driver. * tag 'tegra-for-3.14-powergate' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: ARM: tegra: Add IO rail support ARM: tegra: Special-case the 3D clamps on Tegra124 ARM: tegra: Add Tegra124 powergate support ARM: tegra: Export tegra_powergate_remove_clamping() ARM: tegra: Export tegra_powergate_power_off() ARM: tegra: Rename cpu0 powergate to crail ARM: tegra: Fix some whitespace oddities Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--arch/arm/mach-tegra/powergate.c195
-rw-r--r--include/linux/tegra-powergate.h48
2 files changed, 240 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index f6f5b54ff95e..3d0c537d9b94 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -34,6 +34,10 @@
34#include "fuse.h" 34#include "fuse.h"
35#include "iomap.h" 35#include "iomap.h"
36 36
37#define DPD_SAMPLE 0x020
38#define DPD_SAMPLE_ENABLE (1 << 0)
39#define DPD_SAMPLE_DISABLE (0 << 0)
40
37#define PWRGATE_TOGGLE 0x30 41#define PWRGATE_TOGGLE 0x30
38#define PWRGATE_TOGGLE_START (1 << 8) 42#define PWRGATE_TOGGLE_START (1 << 8)
39 43
@@ -41,6 +45,19 @@
41 45
42#define PWRGATE_STATUS 0x38 46#define PWRGATE_STATUS 0x38
43 47
48#define IO_DPD_REQ 0x1b8
49#define IO_DPD_REQ_CODE_IDLE (0 << 30)
50#define IO_DPD_REQ_CODE_OFF (1 << 30)
51#define IO_DPD_REQ_CODE_ON (2 << 30)
52#define IO_DPD_REQ_CODE_MASK (3 << 30)
53
54#define IO_DPD_STATUS 0x1bc
55#define IO_DPD2_REQ 0x1c0
56#define IO_DPD2_STATUS 0x1c4
57#define SEL_DPD_TIM 0x1c8
58
59#define GPU_RG_CNTRL 0x2d4
60
44static int tegra_num_powerdomains; 61static int tegra_num_powerdomains;
45static int tegra_num_cpu_domains; 62static int tegra_num_cpu_domains;
46static const u8 *tegra_cpu_domains; 63static const u8 *tegra_cpu_domains;
@@ -59,6 +76,13 @@ static const u8 tegra114_cpu_domains[] = {
59 TEGRA_POWERGATE_CPU3, 76 TEGRA_POWERGATE_CPU3,
60}; 77};
61 78
79static const u8 tegra124_cpu_domains[] = {
80 TEGRA_POWERGATE_CPU0,
81 TEGRA_POWERGATE_CPU1,
82 TEGRA_POWERGATE_CPU2,
83 TEGRA_POWERGATE_CPU3,
84};
85
62static DEFINE_SPINLOCK(tegra_powergate_lock); 86static DEFINE_SPINLOCK(tegra_powergate_lock);
63 87
64static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); 88static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -109,6 +133,7 @@ int tegra_powergate_power_off(int id)
109 133
110 return tegra_powergate_set(id, false); 134 return tegra_powergate_set(id, false);
111} 135}
136EXPORT_SYMBOL(tegra_powergate_power_off);
112 137
113int tegra_powergate_is_powered(int id) 138int tegra_powergate_is_powered(int id)
114{ 139{
@@ -129,12 +154,23 @@ int tegra_powergate_remove_clamping(int id)
129 return -EINVAL; 154 return -EINVAL;
130 155
131 /* 156 /*
157 * The Tegra124 GPU has a separate register (with different semantics)
158 * to remove clamps.
159 */
160 if (tegra_chip_id == TEGRA124) {
161 if (id == TEGRA_POWERGATE_3D) {
162 pmc_write(0, GPU_RG_CNTRL);
163 return 0;
164 }
165 }
166
167 /*
132 * Tegra 2 has a bug where PCIE and VDE clamping masks are 168 * Tegra 2 has a bug where PCIE and VDE clamping masks are
133 * swapped relatively to the partition ids 169 * swapped relatively to the partition ids
134 */ 170 */
135 if (id == TEGRA_POWERGATE_VDEC) 171 if (id == TEGRA_POWERGATE_VDEC)
136 mask = (1 << TEGRA_POWERGATE_PCIE); 172 mask = (1 << TEGRA_POWERGATE_PCIE);
137 else if (id == TEGRA_POWERGATE_PCIE) 173 else if (id == TEGRA_POWERGATE_PCIE)
138 mask = (1 << TEGRA_POWERGATE_VDEC); 174 mask = (1 << TEGRA_POWERGATE_VDEC);
139 else 175 else
140 mask = (1 << id); 176 mask = (1 << id);
@@ -143,6 +179,7 @@ int tegra_powergate_remove_clamping(int id)
143 179
144 return 0; 180 return 0;
145} 181}
182EXPORT_SYMBOL(tegra_powergate_remove_clamping);
146 183
147/* Must be called with clk disabled, and returns with clk enabled */ 184/* Must be called with clk disabled, and returns with clk enabled */
148int tegra_powergate_sequence_power_up(int id, struct clk *clk, 185int tegra_powergate_sequence_power_up(int id, struct clk *clk,
@@ -204,6 +241,11 @@ int __init tegra_powergate_init(void)
204 tegra_num_cpu_domains = 4; 241 tegra_num_cpu_domains = 4;
205 tegra_cpu_domains = tegra114_cpu_domains; 242 tegra_cpu_domains = tegra114_cpu_domains;
206 break; 243 break;
244 case TEGRA124:
245 tegra_num_powerdomains = 25;
246 tegra_num_cpu_domains = 4;
247 tegra_cpu_domains = tegra124_cpu_domains;
248 break;
207 default: 249 default:
208 /* Unknown Tegra variant. Disable powergating */ 250 /* Unknown Tegra variant. Disable powergating */
209 tegra_num_powerdomains = 0; 251 tegra_num_powerdomains = 0;
@@ -245,12 +287,36 @@ static const char * const powergate_name_t30[] = {
245}; 287};
246 288
247static const char * const powergate_name_t114[] = { 289static const char * const powergate_name_t114[] = {
248 [TEGRA_POWERGATE_CPU] = "cpu0", 290 [TEGRA_POWERGATE_CPU] = "crail",
291 [TEGRA_POWERGATE_3D] = "3d",
292 [TEGRA_POWERGATE_VENC] = "venc",
293 [TEGRA_POWERGATE_VDEC] = "vdec",
294 [TEGRA_POWERGATE_MPE] = "mpe",
295 [TEGRA_POWERGATE_HEG] = "heg",
296 [TEGRA_POWERGATE_CPU1] = "cpu1",
297 [TEGRA_POWERGATE_CPU2] = "cpu2",
298 [TEGRA_POWERGATE_CPU3] = "cpu3",
299 [TEGRA_POWERGATE_CELP] = "celp",
300 [TEGRA_POWERGATE_CPU0] = "cpu0",
301 [TEGRA_POWERGATE_C0NC] = "c0nc",
302 [TEGRA_POWERGATE_C1NC] = "c1nc",
303 [TEGRA_POWERGATE_DIS] = "dis",
304 [TEGRA_POWERGATE_DISB] = "disb",
305 [TEGRA_POWERGATE_XUSBA] = "xusba",
306 [TEGRA_POWERGATE_XUSBB] = "xusbb",
307 [TEGRA_POWERGATE_XUSBC] = "xusbc",
308};
309
310static const char * const powergate_name_t124[] = {
311 [TEGRA_POWERGATE_CPU] = "crail",
249 [TEGRA_POWERGATE_3D] = "3d", 312 [TEGRA_POWERGATE_3D] = "3d",
250 [TEGRA_POWERGATE_VENC] = "venc", 313 [TEGRA_POWERGATE_VENC] = "venc",
314 [TEGRA_POWERGATE_PCIE] = "pcie",
251 [TEGRA_POWERGATE_VDEC] = "vdec", 315 [TEGRA_POWERGATE_VDEC] = "vdec",
316 [TEGRA_POWERGATE_L2] = "l2",
252 [TEGRA_POWERGATE_MPE] = "mpe", 317 [TEGRA_POWERGATE_MPE] = "mpe",
253 [TEGRA_POWERGATE_HEG] = "heg", 318 [TEGRA_POWERGATE_HEG] = "heg",
319 [TEGRA_POWERGATE_SATA] = "sata",
254 [TEGRA_POWERGATE_CPU1] = "cpu1", 320 [TEGRA_POWERGATE_CPU1] = "cpu1",
255 [TEGRA_POWERGATE_CPU2] = "cpu2", 321 [TEGRA_POWERGATE_CPU2] = "cpu2",
256 [TEGRA_POWERGATE_CPU3] = "cpu3", 322 [TEGRA_POWERGATE_CPU3] = "cpu3",
@@ -258,11 +324,14 @@ static const char * const powergate_name_t114[] = {
258 [TEGRA_POWERGATE_CPU0] = "cpu0", 324 [TEGRA_POWERGATE_CPU0] = "cpu0",
259 [TEGRA_POWERGATE_C0NC] = "c0nc", 325 [TEGRA_POWERGATE_C0NC] = "c0nc",
260 [TEGRA_POWERGATE_C1NC] = "c1nc", 326 [TEGRA_POWERGATE_C1NC] = "c1nc",
327 [TEGRA_POWERGATE_SOR] = "sor",
261 [TEGRA_POWERGATE_DIS] = "dis", 328 [TEGRA_POWERGATE_DIS] = "dis",
262 [TEGRA_POWERGATE_DISB] = "disb", 329 [TEGRA_POWERGATE_DISB] = "disb",
263 [TEGRA_POWERGATE_XUSBA] = "xusba", 330 [TEGRA_POWERGATE_XUSBA] = "xusba",
264 [TEGRA_POWERGATE_XUSBB] = "xusbb", 331 [TEGRA_POWERGATE_XUSBB] = "xusbb",
265 [TEGRA_POWERGATE_XUSBC] = "xusbc", 332 [TEGRA_POWERGATE_XUSBC] = "xusbc",
333 [TEGRA_POWERGATE_VIC] = "vic",
334 [TEGRA_POWERGATE_IRAM] = "iram",
266}; 335};
267 336
268static int powergate_show(struct seq_file *s, void *data) 337static int powergate_show(struct seq_file *s, void *data)
@@ -309,6 +378,9 @@ int __init tegra_powergate_debugfs_init(void)
309 case TEGRA114: 378 case TEGRA114:
310 powergate_name = powergate_name_t114; 379 powergate_name = powergate_name_t114;
311 break; 380 break;
381 case TEGRA124:
382 powergate_name = powergate_name_t124;
383 break;
312 } 384 }
313 385
314 if (powergate_name) { 386 if (powergate_name) {
@@ -322,3 +394,120 @@ int __init tegra_powergate_debugfs_init(void)
322} 394}
323 395
324#endif 396#endif
397
398static int tegra_io_rail_prepare(int id, unsigned long *request,
399 unsigned long *status, unsigned int *bit)
400{
401 unsigned long rate, value;
402 struct clk *clk;
403
404 *bit = id % 32;
405
406 /*
407 * There are two sets of 30 bits to select IO rails, but bits 30 and
408 * 31 are control bits rather than IO rail selection bits.
409 */
410 if (id > 63 || *bit == 30 || *bit == 31)
411 return -EINVAL;
412
413 if (id < 32) {
414 *status = IO_DPD_STATUS;
415 *request = IO_DPD_REQ;
416 } else {
417 *status = IO_DPD2_STATUS;
418 *request = IO_DPD2_REQ;
419 }
420
421 clk = clk_get_sys(NULL, "pclk");
422 if (IS_ERR(clk))
423 return PTR_ERR(clk);
424
425 rate = clk_get_rate(clk);
426 clk_put(clk);
427
428 pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
429
430 /* must be at least 200 ns, in APB (PCLK) clock cycles */
431 value = DIV_ROUND_UP(1000000000, rate);
432 value = DIV_ROUND_UP(200, value);
433 pmc_write(value, SEL_DPD_TIM);
434
435 return 0;
436}
437
438static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
439 unsigned long val, unsigned long timeout)
440{
441 unsigned long value;
442
443 timeout = jiffies + msecs_to_jiffies(timeout);
444
445 while (time_after(timeout, jiffies)) {
446 value = pmc_read(offset);
447 if ((value & mask) == val)
448 return 0;
449
450 usleep_range(250, 1000);
451 }
452
453 return -ETIMEDOUT;
454}
455
456static void tegra_io_rail_unprepare(void)
457{
458 pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
459}
460
461int tegra_io_rail_power_on(int id)
462{
463 unsigned long request, status, value;
464 unsigned int bit, mask;
465 int err;
466
467 err = tegra_io_rail_prepare(id, &request, &status, &bit);
468 if (err < 0)
469 return err;
470
471 mask = 1 << bit;
472
473 value = pmc_read(request);
474 value |= mask;
475 value &= ~IO_DPD_REQ_CODE_MASK;
476 value |= IO_DPD_REQ_CODE_OFF;
477 pmc_write(value, request);
478
479 err = tegra_io_rail_poll(status, mask, 0, 250);
480 if (err < 0)
481 return err;
482
483 tegra_io_rail_unprepare();
484
485 return 0;
486}
487
488int tegra_io_rail_power_off(int id)
489{
490 unsigned long request, status, value;
491 unsigned int bit, mask;
492 int err;
493
494 err = tegra_io_rail_prepare(id, &request, &status, &bit);
495 if (err < 0)
496 return err;
497
498 mask = 1 << bit;
499
500 value = pmc_read(request);
501 value |= mask;
502 value &= ~IO_DPD_REQ_CODE_MASK;
503 value |= IO_DPD_REQ_CODE_ON;
504 pmc_write(value, request);
505
506 err = tegra_io_rail_poll(status, mask, mask, 250);
507 if (err < 0)
508 return err;
509
510 tegra_io_rail_unprepare();
511
512 return 0;
513}
diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h
index afe442d2629a..e6f2ab3014a7 100644
--- a/include/linux/tegra-powergate.h
+++ b/include/linux/tegra-powergate.h
@@ -38,14 +38,49 @@ struct reset_control;
38#define TEGRA_POWERGATE_CPU0 14 38#define TEGRA_POWERGATE_CPU0 14
39#define TEGRA_POWERGATE_C0NC 15 39#define TEGRA_POWERGATE_C0NC 15
40#define TEGRA_POWERGATE_C1NC 16 40#define TEGRA_POWERGATE_C1NC 16
41#define TEGRA_POWERGATE_SOR 17
41#define TEGRA_POWERGATE_DIS 18 42#define TEGRA_POWERGATE_DIS 18
42#define TEGRA_POWERGATE_DISB 19 43#define TEGRA_POWERGATE_DISB 19
43#define TEGRA_POWERGATE_XUSBA 20 44#define TEGRA_POWERGATE_XUSBA 20
44#define TEGRA_POWERGATE_XUSBB 21 45#define TEGRA_POWERGATE_XUSBB 21
45#define TEGRA_POWERGATE_XUSBC 22 46#define TEGRA_POWERGATE_XUSBC 22
47#define TEGRA_POWERGATE_VIC 23
48#define TEGRA_POWERGATE_IRAM 24
46 49
47#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D 50#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D
48 51
52#define TEGRA_IO_RAIL_CSIA 0
53#define TEGRA_IO_RAIL_CSIB 1
54#define TEGRA_IO_RAIL_DSI 2
55#define TEGRA_IO_RAIL_MIPI_BIAS 3
56#define TEGRA_IO_RAIL_PEX_BIAS 4
57#define TEGRA_IO_RAIL_PEX_CLK1 5
58#define TEGRA_IO_RAIL_PEX_CLK2 6
59#define TEGRA_IO_RAIL_USB0 9
60#define TEGRA_IO_RAIL_USB1 10
61#define TEGRA_IO_RAIL_USB2 11
62#define TEGRA_IO_RAIL_USB_BIAS 12
63#define TEGRA_IO_RAIL_NAND 13
64#define TEGRA_IO_RAIL_UART 14
65#define TEGRA_IO_RAIL_BB 15
66#define TEGRA_IO_RAIL_AUDIO 17
67#define TEGRA_IO_RAIL_HSIC 19
68#define TEGRA_IO_RAIL_COMP 22
69#define TEGRA_IO_RAIL_HDMI 28
70#define TEGRA_IO_RAIL_PEX_CNTRL 32
71#define TEGRA_IO_RAIL_SDMMC1 33
72#define TEGRA_IO_RAIL_SDMMC3 34
73#define TEGRA_IO_RAIL_SDMMC4 35
74#define TEGRA_IO_RAIL_CAM 36
75#define TEGRA_IO_RAIL_RES 37
76#define TEGRA_IO_RAIL_HV 38
77#define TEGRA_IO_RAIL_DSIB 39
78#define TEGRA_IO_RAIL_DSIC 40
79#define TEGRA_IO_RAIL_DSID 41
80#define TEGRA_IO_RAIL_CSIE 44
81#define TEGRA_IO_RAIL_LVDS 57
82#define TEGRA_IO_RAIL_SYS_DDC 58
83
49#ifdef CONFIG_ARCH_TEGRA 84#ifdef CONFIG_ARCH_TEGRA
50int tegra_powergate_is_powered(int id); 85int tegra_powergate_is_powered(int id);
51int tegra_powergate_power_on(int id); 86int tegra_powergate_power_on(int id);
@@ -55,6 +90,9 @@ int tegra_powergate_remove_clamping(int id);
55/* Must be called with clk disabled, and returns with clk enabled */ 90/* Must be called with clk disabled, and returns with clk enabled */
56int tegra_powergate_sequence_power_up(int id, struct clk *clk, 91int tegra_powergate_sequence_power_up(int id, struct clk *clk,
57 struct reset_control *rst); 92 struct reset_control *rst);
93
94int tegra_io_rail_power_on(int id);
95int tegra_io_rail_power_off(int id);
58#else 96#else
59static inline int tegra_powergate_is_powered(int id) 97static inline int tegra_powergate_is_powered(int id)
60{ 98{
@@ -81,6 +119,16 @@ static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk,
81{ 119{
82 return -ENOSYS; 120 return -ENOSYS;
83} 121}
122
123static inline int tegra_io_rail_power_on(int id)
124{
125 return -ENOSYS;
126}
127
128static inline int tegra_io_rail_power_off(int id)
129{
130 return -ENOSYS;
131}
84#endif 132#endif
85 133
86#endif /* _MACH_TEGRA_POWERGATE_H_ */ 134#endif /* _MACH_TEGRA_POWERGATE_H_ */