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>
This commit is contained in:
Thierry Reding 2013-12-16 21:42:28 +01:00 committed by Stephen Warren
parent c537376cbb
commit 9d4450ae87
2 changed files with 177 additions and 0 deletions

View file

@ -34,6 +34,10 @@
#include "fuse.h"
#include "iomap.h"
#define DPD_SAMPLE 0x020
#define DPD_SAMPLE_ENABLE (1 << 0)
#define DPD_SAMPLE_DISABLE (0 << 0)
#define PWRGATE_TOGGLE 0x30
#define PWRGATE_TOGGLE_START (1 << 8)
@ -41,6 +45,17 @@
#define PWRGATE_STATUS 0x38
#define IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30)
#define IO_DPD_REQ_CODE_ON (2 << 30)
#define IO_DPD_REQ_CODE_MASK (3 << 30)
#define IO_DPD_STATUS 0x1bc
#define IO_DPD2_REQ 0x1c0
#define IO_DPD2_STATUS 0x1c4
#define SEL_DPD_TIM 0x1c8
#define GPU_RG_CNTRL 0x2d4
static int tegra_num_powerdomains;
@ -379,3 +394,120 @@ int __init tegra_powergate_debugfs_init(void)
}
#endif
static int tegra_io_rail_prepare(int id, unsigned long *request,
unsigned long *status, unsigned int *bit)
{
unsigned long rate, value;
struct clk *clk;
*bit = id % 32;
/*
* There are two sets of 30 bits to select IO rails, but bits 30 and
* 31 are control bits rather than IO rail selection bits.
*/
if (id > 63 || *bit == 30 || *bit == 31)
return -EINVAL;
if (id < 32) {
*status = IO_DPD_STATUS;
*request = IO_DPD_REQ;
} else {
*status = IO_DPD2_STATUS;
*request = IO_DPD2_REQ;
}
clk = clk_get_sys(NULL, "pclk");
if (IS_ERR(clk))
return PTR_ERR(clk);
rate = clk_get_rate(clk);
clk_put(clk);
pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
/* must be at least 200 ns, in APB (PCLK) clock cycles */
value = DIV_ROUND_UP(1000000000, rate);
value = DIV_ROUND_UP(200, value);
pmc_write(value, SEL_DPD_TIM);
return 0;
}
static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
unsigned long val, unsigned long timeout)
{
unsigned long value;
timeout = jiffies + msecs_to_jiffies(timeout);
while (time_after(timeout, jiffies)) {
value = pmc_read(offset);
if ((value & mask) == val)
return 0;
usleep_range(250, 1000);
}
return -ETIMEDOUT;
}
static void tegra_io_rail_unprepare(void)
{
pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
}
int tegra_io_rail_power_on(int id)
{
unsigned long request, status, value;
unsigned int bit, mask;
int err;
err = tegra_io_rail_prepare(id, &request, &status, &bit);
if (err < 0)
return err;
mask = 1 << bit;
value = pmc_read(request);
value |= mask;
value &= ~IO_DPD_REQ_CODE_MASK;
value |= IO_DPD_REQ_CODE_OFF;
pmc_write(value, request);
err = tegra_io_rail_poll(status, mask, 0, 250);
if (err < 0)
return err;
tegra_io_rail_unprepare();
return 0;
}
int tegra_io_rail_power_off(int id)
{
unsigned long request, status, value;
unsigned int bit, mask;
int err;
err = tegra_io_rail_prepare(id, &request, &status, &bit);
if (err < 0)
return err;
mask = 1 << bit;
value = pmc_read(request);
value |= mask;
value &= ~IO_DPD_REQ_CODE_MASK;
value |= IO_DPD_REQ_CODE_ON;
pmc_write(value, request);
err = tegra_io_rail_poll(status, mask, mask, 250);
if (err < 0)
return err;
tegra_io_rail_unprepare();
return 0;
}

View file

@ -49,6 +49,38 @@ struct reset_control;
#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D
#define TEGRA_IO_RAIL_CSIA 0
#define TEGRA_IO_RAIL_CSIB 1
#define TEGRA_IO_RAIL_DSI 2
#define TEGRA_IO_RAIL_MIPI_BIAS 3
#define TEGRA_IO_RAIL_PEX_BIAS 4
#define TEGRA_IO_RAIL_PEX_CLK1 5
#define TEGRA_IO_RAIL_PEX_CLK2 6
#define TEGRA_IO_RAIL_USB0 9
#define TEGRA_IO_RAIL_USB1 10
#define TEGRA_IO_RAIL_USB2 11
#define TEGRA_IO_RAIL_USB_BIAS 12
#define TEGRA_IO_RAIL_NAND 13
#define TEGRA_IO_RAIL_UART 14
#define TEGRA_IO_RAIL_BB 15
#define TEGRA_IO_RAIL_AUDIO 17
#define TEGRA_IO_RAIL_HSIC 19
#define TEGRA_IO_RAIL_COMP 22
#define TEGRA_IO_RAIL_HDMI 28
#define TEGRA_IO_RAIL_PEX_CNTRL 32
#define TEGRA_IO_RAIL_SDMMC1 33
#define TEGRA_IO_RAIL_SDMMC3 34
#define TEGRA_IO_RAIL_SDMMC4 35
#define TEGRA_IO_RAIL_CAM 36
#define TEGRA_IO_RAIL_RES 37
#define TEGRA_IO_RAIL_HV 38
#define TEGRA_IO_RAIL_DSIB 39
#define TEGRA_IO_RAIL_DSIC 40
#define TEGRA_IO_RAIL_DSID 41
#define TEGRA_IO_RAIL_CSIE 44
#define TEGRA_IO_RAIL_LVDS 57
#define TEGRA_IO_RAIL_SYS_DDC 58
#ifdef CONFIG_ARCH_TEGRA
int tegra_powergate_is_powered(int id);
int tegra_powergate_power_on(int id);
@ -58,6 +90,9 @@ int tegra_powergate_remove_clamping(int id);
/* Must be called with clk disabled, and returns with clk enabled */
int tegra_powergate_sequence_power_up(int id, struct clk *clk,
struct reset_control *rst);
int tegra_io_rail_power_on(int id);
int tegra_io_rail_power_off(int id);
#else
static inline int tegra_powergate_is_powered(int id)
{
@ -84,6 +119,16 @@ static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk,
{
return -ENOSYS;
}
static inline int tegra_io_rail_power_on(int id)
{
return -ENOSYS;
}
static inline int tegra_io_rail_power_off(int id)
{
return -ENOSYS;
}
#endif
#endif /* _MACH_TEGRA_POWERGATE_H_ */