Skip to content

Commit

Permalink
ARM: tegra: Add IO rail support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Thierry Reding authored and Stephen Warren committed Dec 16, 2013
1 parent c537376 commit 9d4450a
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
132 changes: 132 additions & 0 deletions arch/arm/mach-tegra/powergate.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,28 @@
#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)

#define REMOVE_CLAMPING 0x34

#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;
Expand Down Expand Up @@ -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;
}
45 changes: 45 additions & 0 deletions include/linux/tegra-powergate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
{
Expand All @@ -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_ */

0 comments on commit 9d4450a

Please sign in to comment.