Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d4450ae authored by Thierry Reding's avatar Thierry Reding Committed by Stephen Warren
Browse files

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: default avatarThierry Reding <treding@nvidia.com>
Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
parent c537376c
Loading
Loading
Loading
Loading
+132 −0
Original line number Diff line number Diff line
@@ -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;
}
+45 −0
Original line number Diff line number Diff line
@@ -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_ */