aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorThierry Reding <thierry.reding@gmail.com>2013-12-16 15:42:28 -0500
committerStephen Warren <swarren@nvidia.com>2013-12-16 16:03:09 -0500
commit9d4450ae87398e248e8700e3507748e0d1751e25 (patch)
treeeef26d8d35fe258e6b67531bcc38ec98a327be4c /arch/arm/mach-tegra
parentc537376cbbbfea2b741b39ad37d5b44104b66e56 (diff)
ARM: tegra: Add IO rail support
Add tegra_io_rail_power_off() and tegra_io_rail_power_on() functions to put IO rails into or out of deep powerdown mode, respectively. Signed-off-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/powergate.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 0026fb6c984b..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,17 @@
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
44#define GPU_RG_CNTRL 0x2d4 59#define GPU_RG_CNTRL 0x2d4
45 60
46static int tegra_num_powerdomains; 61static int tegra_num_powerdomains;
@@ -379,3 +394,120 @@ int __init tegra_powergate_debugfs_init(void)
379} 394}
380 395
381#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}