diff mbox series

[1/3] soc/tegra: pmc: set IO pad power state and voltage via pinctrl fw

Message ID 1533211143-17517-1-git-send-email-vreddytalla@nvidia.com
State Superseded
Headers show
Series [1/3] soc/tegra: pmc: set IO pad power state and voltage via pinctrl fw | expand

Commit Message

Venkat Reddy Talla Aug. 2, 2018, 11:59 a.m. UTC
The IO pins of Tegra SoCs are grouped for common control
of IO interface like setting voltage signal levels and
power state of the interface. These groups are referred
to as IO pads.The power state and voltage control of IO pins
can be done at IO pads level.

Tegra SoCs support powering down IO pads when they are
not used even in the active state of system.
This saves power from that IO interface. Also it supports
multiple voltage level in IO pins for interfacing on
some of pads. The IO pad voltage is automatically detected
till Tegra124, hence SW need not to configure this.
But from Tegra210, the automatic detection logic has been
removed, hence SW need to explicitly set the IO pad
voltage into IO pad configuration registers.

Add support to configure the power state and voltage level
of the IO pads from client driver via pincontrol framework.

Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
---
 drivers/soc/tegra/pmc.c | 891 +++++++++++++++++++++++++++++++++++++-----------
 include/soc/tegra/pmc.h |  21 +-
 2 files changed, 701 insertions(+), 211 deletions(-)

Comments

Jon Hunter Aug. 2, 2018, 12:21 p.m. UTC | #1
On 02/08/18 12:59, Venkat Reddy Talla wrote:
> The IO pins of Tegra SoCs are grouped for common control
> of IO interface like setting voltage signal levels and
> power state of the interface. These groups are referred
> to as IO pads.The power state and voltage control of IO pins
> can be done at IO pads level.
> 
> Tegra SoCs support powering down IO pads when they are
> not used even in the active state of system.
> This saves power from that IO interface. Also it supports
> multiple voltage level in IO pins for interfacing on
> some of pads. The IO pad voltage is automatically detected
> till Tegra124, hence SW need not to configure this.
> But from Tegra210, the automatic detection logic has been
> removed, hence SW need to explicitly set the IO pad
> voltage into IO pad configuration registers.
> 
> Add support to configure the power state and voltage level
> of the IO pads from client driver via pincontrol framework.
> 
> Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>

This appears to be a duplicate effort of the following which we have
been reviewing ...

https://marc.info/?l=linux-tegra&m=153295930808915&w=2

Cheers
Jon
kernel test robot Aug. 2, 2018, 10:21 p.m. UTC | #2
Hi Venkat,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on tegra/for-next]
[also build test ERROR on v4.18-rc7 next-20180802]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Venkat-Reddy-Talla/soc-tegra-pmc-set-IO-pad-power-state-and-voltage-via-pinctrl-fw/20180803-043413
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=arm64 

All errors (new ones prefixed by >>):

>> drivers/soc/tegra/pmc.c:51:10: fatal error: dt-bindings/pinctrl/pinctrl-tegra-io-pad.h: No such file or directory
    #include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   compilation terminated.

vim +51 drivers/soc/tegra/pmc.c

    50	
  > 51	#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
    52	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot Aug. 2, 2018, 10:45 p.m. UTC | #3
Hi Venkat,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on tegra/for-next]
[also build test ERROR on v4.18-rc7 next-20180802]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Venkat-Reddy-Talla/soc-tegra-pmc-set-IO-pad-power-state-and-voltage-via-pinctrl-fw/20180803-043413
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=arm64 

Note: the linux-review/Venkat-Reddy-Talla/soc-tegra-pmc-set-IO-pad-power-state-and-voltage-via-pinctrl-fw/20180803-043413 HEAD ab02915682b2d61932e12e719422af7bc05b1eef builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

   drivers/gpu//drm/tegra/sor.c: In function 'tegra_sor_edp_disable':
>> drivers/gpu//drm/tegra/sor.c:1550:8: error: implicit declaration of function 'tegra_io_pad_power_disable'; did you mean 'tegra_pmc_io_pad_low_power_disable'? [-Werror=implicit-function-declaration]
     err = tegra_io_pad_power_disable(sor->pad);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~
           tegra_pmc_io_pad_low_power_disable
   drivers/gpu//drm/tegra/sor.c: In function 'tegra_sor_edp_enable':
>> drivers/gpu//drm/tegra/sor.c:1710:8: error: implicit declaration of function 'tegra_io_pad_power_enable'; did you mean 'tegra_io_rail_power_on'? [-Werror=implicit-function-declaration]
     err = tegra_io_pad_power_enable(sor->pad);
           ^~~~~~~~~~~~~~~~~~~~~~~~~
           tegra_io_rail_power_on
   cc1: some warnings being treated as errors

vim +1550 drivers/gpu//drm/tegra/sor.c

6fad8f66d Thierry Reding     2014-11-28  1509  
850bab448 Thierry Reding     2015-07-29  1510  static void tegra_sor_edp_disable(struct drm_encoder *encoder)
6fad8f66d Thierry Reding     2014-11-28  1511  {
850bab448 Thierry Reding     2015-07-29  1512  	struct tegra_output *output = encoder_to_output(encoder);
850bab448 Thierry Reding     2015-07-29  1513  	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
850bab448 Thierry Reding     2015-07-29  1514  	struct tegra_sor *sor = to_sor(output);
850bab448 Thierry Reding     2015-07-29  1515  	u32 value;
850bab448 Thierry Reding     2015-07-29  1516  	int err;
850bab448 Thierry Reding     2015-07-29  1517  
850bab448 Thierry Reding     2015-07-29  1518  	if (output->panel)
850bab448 Thierry Reding     2015-07-29  1519  		drm_panel_disable(output->panel);
850bab448 Thierry Reding     2015-07-29  1520  
850bab448 Thierry Reding     2015-07-29  1521  	err = tegra_sor_detach(sor);
850bab448 Thierry Reding     2015-07-29  1522  	if (err < 0)
850bab448 Thierry Reding     2015-07-29  1523  		dev_err(sor->dev, "failed to detach SOR: %d\n", err);
850bab448 Thierry Reding     2015-07-29  1524  
850bab448 Thierry Reding     2015-07-29  1525  	tegra_sor_writel(sor, 0, SOR_STATE1);
850bab448 Thierry Reding     2015-07-29  1526  	tegra_sor_update(sor);
850bab448 Thierry Reding     2015-07-29  1527  
850bab448 Thierry Reding     2015-07-29  1528  	/*
850bab448 Thierry Reding     2015-07-29  1529  	 * The following accesses registers of the display controller, so make
850bab448 Thierry Reding     2015-07-29  1530  	 * sure it's only executed when the output is attached to one.
850bab448 Thierry Reding     2015-07-29  1531  	 */
850bab448 Thierry Reding     2015-07-29  1532  	if (dc) {
850bab448 Thierry Reding     2015-07-29  1533  		value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
c57997bce Thierry Reding     2017-10-12  1534  		value &= ~SOR_ENABLE(0);
850bab448 Thierry Reding     2015-07-29  1535  		tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
850bab448 Thierry Reding     2015-07-29  1536  
850bab448 Thierry Reding     2015-07-29  1537  		tegra_dc_commit(dc);
6fad8f66d Thierry Reding     2014-11-28  1538  	}
6fad8f66d Thierry Reding     2014-11-28  1539  
850bab448 Thierry Reding     2015-07-29  1540  	err = tegra_sor_power_down(sor);
850bab448 Thierry Reding     2015-07-29  1541  	if (err < 0)
850bab448 Thierry Reding     2015-07-29  1542  		dev_err(sor->dev, "failed to power down SOR: %d\n", err);
850bab448 Thierry Reding     2015-07-29  1543  
9542c2376 Thierry Reding     2015-07-08  1544  	if (sor->aux) {
9542c2376 Thierry Reding     2015-07-08  1545  		err = drm_dp_aux_disable(sor->aux);
850bab448 Thierry Reding     2015-07-29  1546  		if (err < 0)
850bab448 Thierry Reding     2015-07-29  1547  			dev_err(sor->dev, "failed to disable DP: %d\n", err);
6fad8f66d Thierry Reding     2014-11-28  1548  	}
6fad8f66d Thierry Reding     2014-11-28  1549  
c57997bce Thierry Reding     2017-10-12 @1550  	err = tegra_io_pad_power_disable(sor->pad);
850bab448 Thierry Reding     2015-07-29  1551  	if (err < 0)
c57997bce Thierry Reding     2017-10-12  1552  		dev_err(sor->dev, "failed to power off I/O pad: %d\n", err);
850bab448 Thierry Reding     2015-07-29  1553  
850bab448 Thierry Reding     2015-07-29  1554  	if (output->panel)
850bab448 Thierry Reding     2015-07-29  1555  		drm_panel_unprepare(output->panel);
850bab448 Thierry Reding     2015-07-29  1556  
aaff8bd2e Thierry Reding     2015-08-07  1557  	pm_runtime_put(sor->dev);
6fad8f66d Thierry Reding     2014-11-28  1558  }
6fad8f66d Thierry Reding     2014-11-28  1559  
459cc2c68 Thierry Reding     2015-07-30  1560  #if 0
459cc2c68 Thierry Reding     2015-07-30  1561  static int calc_h_ref_to_sync(const struct drm_display_mode *mode,
459cc2c68 Thierry Reding     2015-07-30  1562  			      unsigned int *value)
459cc2c68 Thierry Reding     2015-07-30  1563  {
459cc2c68 Thierry Reding     2015-07-30  1564  	unsigned int hfp, hsw, hbp, a = 0, b;
459cc2c68 Thierry Reding     2015-07-30  1565  
459cc2c68 Thierry Reding     2015-07-30  1566  	hfp = mode->hsync_start - mode->hdisplay;
459cc2c68 Thierry Reding     2015-07-30  1567  	hsw = mode->hsync_end - mode->hsync_start;
459cc2c68 Thierry Reding     2015-07-30  1568  	hbp = mode->htotal - mode->hsync_end;
459cc2c68 Thierry Reding     2015-07-30  1569  
459cc2c68 Thierry Reding     2015-07-30  1570  	pr_info("hfp: %u, hsw: %u, hbp: %u\n", hfp, hsw, hbp);
459cc2c68 Thierry Reding     2015-07-30  1571  
459cc2c68 Thierry Reding     2015-07-30  1572  	b = hfp - 1;
459cc2c68 Thierry Reding     2015-07-30  1573  
459cc2c68 Thierry Reding     2015-07-30  1574  	pr_info("a: %u, b: %u\n", a, b);
459cc2c68 Thierry Reding     2015-07-30  1575  	pr_info("a + hsw + hbp = %u\n", a + hsw + hbp);
459cc2c68 Thierry Reding     2015-07-30  1576  
459cc2c68 Thierry Reding     2015-07-30  1577  	if (a + hsw + hbp <= 11) {
459cc2c68 Thierry Reding     2015-07-30  1578  		a = 1 + 11 - hsw - hbp;
459cc2c68 Thierry Reding     2015-07-30  1579  		pr_info("a: %u\n", a);
459cc2c68 Thierry Reding     2015-07-30  1580  	}
459cc2c68 Thierry Reding     2015-07-30  1581  
459cc2c68 Thierry Reding     2015-07-30  1582  	if (a > b)
459cc2c68 Thierry Reding     2015-07-30  1583  		return -EINVAL;
459cc2c68 Thierry Reding     2015-07-30  1584  
459cc2c68 Thierry Reding     2015-07-30  1585  	if (hsw < 1)
459cc2c68 Thierry Reding     2015-07-30  1586  		return -EINVAL;
459cc2c68 Thierry Reding     2015-07-30  1587  
459cc2c68 Thierry Reding     2015-07-30  1588  	if (mode->hdisplay < 16)
459cc2c68 Thierry Reding     2015-07-30  1589  		return -EINVAL;
459cc2c68 Thierry Reding     2015-07-30  1590  
459cc2c68 Thierry Reding     2015-07-30  1591  	if (value) {
459cc2c68 Thierry Reding     2015-07-30  1592  		if (b > a && a % 2)
459cc2c68 Thierry Reding     2015-07-30  1593  			*value = a + 1;
459cc2c68 Thierry Reding     2015-07-30  1594  		else
459cc2c68 Thierry Reding     2015-07-30  1595  			*value = a;
459cc2c68 Thierry Reding     2015-07-30  1596  	}
459cc2c68 Thierry Reding     2015-07-30  1597  
459cc2c68 Thierry Reding     2015-07-30  1598  	return 0;
459cc2c68 Thierry Reding     2015-07-30  1599  }
459cc2c68 Thierry Reding     2015-07-30  1600  #endif
459cc2c68 Thierry Reding     2015-07-30  1601  
850bab448 Thierry Reding     2015-07-29  1602  static void tegra_sor_edp_enable(struct drm_encoder *encoder)
6fad8f66d Thierry Reding     2014-11-28  1603  {
850bab448 Thierry Reding     2015-07-29  1604  	struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
6fad8f66d Thierry Reding     2014-11-28  1605  	struct tegra_output *output = encoder_to_output(encoder);
6fad8f66d Thierry Reding     2014-11-28  1606  	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
6b6b60421 Thierry Reding     2013-11-15  1607  	struct tegra_sor *sor = to_sor(output);
34fa183ba Thierry Reding     2014-06-05  1608  	struct tegra_sor_config config;
c31efa7a3 Thierry Reding     2015-09-08  1609  	struct tegra_sor_state *state;
34fa183ba Thierry Reding     2014-06-05  1610  	struct drm_dp_link link;
01b9bea0c Thierry Reding     2015-11-11  1611  	u8 rate, lanes;
2bd1dd399 Thierry Reding     2015-08-03  1612  	unsigned int i;
86f5c52dc Thierry Reding     2014-03-26  1613  	int err = 0;
28fe20760 Thierry Reding     2015-01-26  1614  	u32 value;
86f5c52dc Thierry Reding     2014-03-26  1615  
c31efa7a3 Thierry Reding     2015-09-08  1616  	state = to_sor_state(output->connector.state);
6b6b60421 Thierry Reding     2013-11-15  1617  
aaff8bd2e Thierry Reding     2015-08-07  1618  	pm_runtime_get_sync(sor->dev);
6b6b60421 Thierry Reding     2013-11-15  1619  
6fad8f66d Thierry Reding     2014-11-28  1620  	if (output->panel)
6fad8f66d Thierry Reding     2014-11-28  1621  		drm_panel_prepare(output->panel);
6fad8f66d Thierry Reding     2014-11-28  1622  
9542c2376 Thierry Reding     2015-07-08  1623  	err = drm_dp_aux_enable(sor->aux);
6b6b60421 Thierry Reding     2013-11-15  1624  	if (err < 0)
6b6b60421 Thierry Reding     2013-11-15  1625  		dev_err(sor->dev, "failed to enable DP: %d\n", err);
34fa183ba Thierry Reding     2014-06-05  1626  
9542c2376 Thierry Reding     2015-07-08  1627  	err = drm_dp_link_probe(sor->aux, &link);
34fa183ba Thierry Reding     2014-06-05  1628  	if (err < 0) {
01b9bea0c Thierry Reding     2015-11-11  1629  		dev_err(sor->dev, "failed to probe eDP link: %d\n", err);
850bab448 Thierry Reding     2015-07-29  1630  		return;
34fa183ba Thierry Reding     2014-06-05  1631  	}
6b6b60421 Thierry Reding     2013-11-15  1632  
25bb2cec8 Thierry Reding     2015-08-03  1633  	/* switch to safe parent clock */
25bb2cec8 Thierry Reding     2015-08-03  1634  	err = tegra_sor_set_parent_clock(sor, sor->clk_safe);
6b6b60421 Thierry Reding     2013-11-15  1635  	if (err < 0)
6b6b60421 Thierry Reding     2013-11-15  1636  		dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1637  
34fa183ba Thierry Reding     2014-06-05  1638  	memset(&config, 0, sizeof(config));
c31efa7a3 Thierry Reding     2015-09-08  1639  	config.bits_per_pixel = state->bpc * 3;
34fa183ba Thierry Reding     2014-06-05  1640  
a198359e3 Thierry Reding     2015-07-21  1641  	err = tegra_sor_compute_config(sor, mode, &config, &link);
34fa183ba Thierry Reding     2014-06-05  1642  	if (err < 0)
a198359e3 Thierry Reding     2015-07-21  1643  		dev_err(sor->dev, "failed to compute configuration: %d\n", err);
34fa183ba Thierry Reding     2014-06-05  1644  
6b6b60421 Thierry Reding     2013-11-15  1645  	value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1646  	value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
6b6b60421 Thierry Reding     2013-11-15  1647  	value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
6b6b60421 Thierry Reding     2013-11-15  1648  	tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1649  
880cee0b7 Thierry Reding     2017-10-12  1650  	value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1651  	value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
880cee0b7 Thierry Reding     2017-10-12  1652  	tegra_sor_writel(sor, value, sor->soc->regs->pll2);
6b6b60421 Thierry Reding     2013-11-15  1653  	usleep_range(20, 100);
6b6b60421 Thierry Reding     2013-11-15  1654  
880cee0b7 Thierry Reding     2017-10-12  1655  	value = tegra_sor_readl(sor, sor->soc->regs->pll3);
a9a9e4fd7 Thierry Reding     2015-04-27  1656  	value |= SOR_PLL3_PLL_VDD_MODE_3V3;
880cee0b7 Thierry Reding     2017-10-12  1657  	tegra_sor_writel(sor, value, sor->soc->regs->pll3);
6b6b60421 Thierry Reding     2013-11-15  1658  
a9a9e4fd7 Thierry Reding     2015-04-27  1659  	value = SOR_PLL0_ICHPMP(0xf) | SOR_PLL0_VCOCAP_RST |
a9a9e4fd7 Thierry Reding     2015-04-27  1660  		SOR_PLL0_PLLREG_LEVEL_V45 | SOR_PLL0_RESISTOR_EXT;
880cee0b7 Thierry Reding     2017-10-12  1661  	tegra_sor_writel(sor, value, sor->soc->regs->pll0);
6b6b60421 Thierry Reding     2013-11-15  1662  
880cee0b7 Thierry Reding     2017-10-12  1663  	value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1664  	value |= SOR_PLL2_SEQ_PLLCAPPD;
a9a9e4fd7 Thierry Reding     2015-04-27  1665  	value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
a9a9e4fd7 Thierry Reding     2015-04-27  1666  	value |= SOR_PLL2_LVDS_ENABLE;
880cee0b7 Thierry Reding     2017-10-12  1667  	tegra_sor_writel(sor, value, sor->soc->regs->pll2);
6b6b60421 Thierry Reding     2013-11-15  1668  
a9a9e4fd7 Thierry Reding     2015-04-27  1669  	value = SOR_PLL1_TERM_COMPOUT | SOR_PLL1_TMDS_TERM;
880cee0b7 Thierry Reding     2017-10-12  1670  	tegra_sor_writel(sor, value, sor->soc->regs->pll1);
6b6b60421 Thierry Reding     2013-11-15  1671  
6b6b60421 Thierry Reding     2013-11-15  1672  	while (true) {
880cee0b7 Thierry Reding     2017-10-12  1673  		value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1674  		if ((value & SOR_PLL2_SEQ_PLLCAPPD_ENFORCE) == 0)
6b6b60421 Thierry Reding     2013-11-15  1675  			break;
6b6b60421 Thierry Reding     2013-11-15  1676  
6b6b60421 Thierry Reding     2013-11-15  1677  		usleep_range(250, 1000);
6b6b60421 Thierry Reding     2013-11-15  1678  	}
6b6b60421 Thierry Reding     2013-11-15  1679  
880cee0b7 Thierry Reding     2017-10-12  1680  	value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1681  	value &= ~SOR_PLL2_POWERDOWN_OVERRIDE;
a9a9e4fd7 Thierry Reding     2015-04-27  1682  	value &= ~SOR_PLL2_PORT_POWERDOWN;
880cee0b7 Thierry Reding     2017-10-12  1683  	tegra_sor_writel(sor, value, sor->soc->regs->pll2);
6b6b60421 Thierry Reding     2013-11-15  1684  
6b6b60421 Thierry Reding     2013-11-15  1685  	/*
6b6b60421 Thierry Reding     2013-11-15  1686  	 * power up
6b6b60421 Thierry Reding     2013-11-15  1687  	 */
6b6b60421 Thierry Reding     2013-11-15  1688  
6b6b60421 Thierry Reding     2013-11-15  1689  	/* set safe link bandwidth (1.62 Gbps) */
6b6b60421 Thierry Reding     2013-11-15  1690  	value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1691  	value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
6b6b60421 Thierry Reding     2013-11-15  1692  	value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62;
6b6b60421 Thierry Reding     2013-11-15  1693  	tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1694  
6b6b60421 Thierry Reding     2013-11-15  1695  	/* step 1 */
880cee0b7 Thierry Reding     2017-10-12  1696  	value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1697  	value |= SOR_PLL2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL2_PORT_POWERDOWN |
a9a9e4fd7 Thierry Reding     2015-04-27  1698  		 SOR_PLL2_BANDGAP_POWERDOWN;
880cee0b7 Thierry Reding     2017-10-12  1699  	tegra_sor_writel(sor, value, sor->soc->regs->pll2);
6b6b60421 Thierry Reding     2013-11-15  1700  
880cee0b7 Thierry Reding     2017-10-12  1701  	value = tegra_sor_readl(sor, sor->soc->regs->pll0);
a9a9e4fd7 Thierry Reding     2015-04-27  1702  	value |= SOR_PLL0_VCOPD | SOR_PLL0_PWR;
880cee0b7 Thierry Reding     2017-10-12  1703  	tegra_sor_writel(sor, value, sor->soc->regs->pll0);
6b6b60421 Thierry Reding     2013-11-15  1704  
880cee0b7 Thierry Reding     2017-10-12  1705  	value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0);
6b6b60421 Thierry Reding     2013-11-15  1706  	value &= ~SOR_DP_PADCTL_PAD_CAL_PD;
880cee0b7 Thierry Reding     2017-10-12  1707  	tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0);
6b6b60421 Thierry Reding     2013-11-15  1708  
6b6b60421 Thierry Reding     2013-11-15  1709  	/* step 2 */
c57997bce Thierry Reding     2017-10-12 @1710  	err = tegra_io_pad_power_enable(sor->pad);
850bab448 Thierry Reding     2015-07-29  1711  	if (err < 0)
c57997bce Thierry Reding     2017-10-12  1712  		dev_err(sor->dev, "failed to power on I/O pad: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1713  
6b6b60421 Thierry Reding     2013-11-15  1714  	usleep_range(5, 100);
6b6b60421 Thierry Reding     2013-11-15  1715  
6b6b60421 Thierry Reding     2013-11-15  1716  	/* step 3 */
880cee0b7 Thierry Reding     2017-10-12  1717  	value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1718  	value &= ~SOR_PLL2_BANDGAP_POWERDOWN;
880cee0b7 Thierry Reding     2017-10-12  1719  	tegra_sor_writel(sor, value, sor->soc->regs->pll2);
6b6b60421 Thierry Reding     2013-11-15  1720  
6b6b60421 Thierry Reding     2013-11-15  1721  	usleep_range(20, 100);
6b6b60421 Thierry Reding     2013-11-15  1722  
6b6b60421 Thierry Reding     2013-11-15  1723  	/* step 4 */
880cee0b7 Thierry Reding     2017-10-12  1724  	value = tegra_sor_readl(sor, sor->soc->regs->pll0);
a9a9e4fd7 Thierry Reding     2015-04-27  1725  	value &= ~SOR_PLL0_VCOPD;
a9a9e4fd7 Thierry Reding     2015-04-27  1726  	value &= ~SOR_PLL0_PWR;
880cee0b7 Thierry Reding     2017-10-12  1727  	tegra_sor_writel(sor, value, sor->soc->regs->pll0);
6b6b60421 Thierry Reding     2013-11-15  1728  
880cee0b7 Thierry Reding     2017-10-12  1729  	value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1730  	value &= ~SOR_PLL2_SEQ_PLLCAPPD_ENFORCE;
880cee0b7 Thierry Reding     2017-10-12  1731  	tegra_sor_writel(sor, value, sor->soc->regs->pll2);
6b6b60421 Thierry Reding     2013-11-15  1732  
6b6b60421 Thierry Reding     2013-11-15  1733  	usleep_range(200, 1000);
6b6b60421 Thierry Reding     2013-11-15  1734  
6b6b60421 Thierry Reding     2013-11-15  1735  	/* step 5 */
880cee0b7 Thierry Reding     2017-10-12  1736  	value = tegra_sor_readl(sor, sor->soc->regs->pll2);
a9a9e4fd7 Thierry Reding     2015-04-27  1737  	value &= ~SOR_PLL2_PORT_POWERDOWN;
880cee0b7 Thierry Reding     2017-10-12  1738  	tegra_sor_writel(sor, value, sor->soc->regs->pll2);
6b6b60421 Thierry Reding     2013-11-15  1739  
30b494355 Thierry Reding     2015-08-03  1740  	/* XXX not in TRM */
30b494355 Thierry Reding     2015-08-03  1741  	for (value = 0, i = 0; i < 5; i++)
30b494355 Thierry Reding     2015-08-03  1742  		value |= SOR_XBAR_CTRL_LINK0_XSEL(i, sor->soc->xbar_cfg[i]) |
30b494355 Thierry Reding     2015-08-03  1743  			 SOR_XBAR_CTRL_LINK1_XSEL(i, i);
30b494355 Thierry Reding     2015-08-03  1744  
30b494355 Thierry Reding     2015-08-03  1745  	tegra_sor_writel(sor, 0x00000000, SOR_XBAR_POL);
30b494355 Thierry Reding     2015-08-03  1746  	tegra_sor_writel(sor, value, SOR_XBAR_CTRL);
30b494355 Thierry Reding     2015-08-03  1747  
25bb2cec8 Thierry Reding     2015-08-03  1748  	/* switch to DP parent clock */
25bb2cec8 Thierry Reding     2015-08-03  1749  	err = tegra_sor_set_parent_clock(sor, sor->clk_dp);
6b6b60421 Thierry Reding     2013-11-15  1750  	if (err < 0)
25bb2cec8 Thierry Reding     2015-08-03  1751  		dev_err(sor->dev, "failed to set parent clock: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1752  
899451b78 Thierry Reding     2014-06-05  1753  	/* power DP lanes */
880cee0b7 Thierry Reding     2017-10-12  1754  	value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0);
899451b78 Thierry Reding     2014-06-05  1755  
899451b78 Thierry Reding     2014-06-05  1756  	if (link.num_lanes <= 2)
899451b78 Thierry Reding     2014-06-05  1757  		value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2);
899451b78 Thierry Reding     2014-06-05  1758  	else
899451b78 Thierry Reding     2014-06-05  1759  		value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_2;
899451b78 Thierry Reding     2014-06-05  1760  
899451b78 Thierry Reding     2014-06-05  1761  	if (link.num_lanes <= 1)
899451b78 Thierry Reding     2014-06-05  1762  		value &= ~SOR_DP_PADCTL_PD_TXD_1;
899451b78 Thierry Reding     2014-06-05  1763  	else
899451b78 Thierry Reding     2014-06-05  1764  		value |= SOR_DP_PADCTL_PD_TXD_1;
899451b78 Thierry Reding     2014-06-05  1765  
899451b78 Thierry Reding     2014-06-05  1766  	if (link.num_lanes == 0)
899451b78 Thierry Reding     2014-06-05  1767  		value &= ~SOR_DP_PADCTL_PD_TXD_0;
899451b78 Thierry Reding     2014-06-05  1768  	else
899451b78 Thierry Reding     2014-06-05  1769  		value |= SOR_DP_PADCTL_PD_TXD_0;
899451b78 Thierry Reding     2014-06-05  1770  
880cee0b7 Thierry Reding     2017-10-12  1771  	tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0);
6b6b60421 Thierry Reding     2013-11-15  1772  
a9a9e4fd7 Thierry Reding     2015-04-27  1773  	value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
6b6b60421 Thierry Reding     2013-11-15  1774  	value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
0c90a1846 Thierry Reding     2014-06-05  1775  	value |= SOR_DP_LINKCTL_LANE_COUNT(link.num_lanes);
a9a9e4fd7 Thierry Reding     2015-04-27  1776  	tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
6b6b60421 Thierry Reding     2013-11-15  1777  
6b6b60421 Thierry Reding     2013-11-15  1778  	/* start lane sequencer */
6b6b60421 Thierry Reding     2013-11-15  1779  	value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
6b6b60421 Thierry Reding     2013-11-15  1780  		SOR_LANE_SEQ_CTL_POWER_STATE_UP;
6b6b60421 Thierry Reding     2013-11-15  1781  	tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
6b6b60421 Thierry Reding     2013-11-15  1782  
6b6b60421 Thierry Reding     2013-11-15  1783  	while (true) {
6b6b60421 Thierry Reding     2013-11-15  1784  		value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
6b6b60421 Thierry Reding     2013-11-15  1785  		if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
6b6b60421 Thierry Reding     2013-11-15  1786  			break;
6b6b60421 Thierry Reding     2013-11-15  1787  
6b6b60421 Thierry Reding     2013-11-15  1788  		usleep_range(250, 1000);
6b6b60421 Thierry Reding     2013-11-15  1789  	}
6b6b60421 Thierry Reding     2013-11-15  1790  
a4263fed2 Thierry Reding     2014-06-05  1791  	/* set link bandwidth */
6b6b60421 Thierry Reding     2013-11-15  1792  	value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1793  	value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
a4263fed2 Thierry Reding     2014-06-05  1794  	value |= drm_dp_link_rate_to_bw_code(link.rate) << 2;
6b6b60421 Thierry Reding     2013-11-15  1795  	tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1796  
402f6bcd9 Thierry Reding     2015-07-21  1797  	tegra_sor_apply_config(sor, &config);
402f6bcd9 Thierry Reding     2015-07-21  1798  
402f6bcd9 Thierry Reding     2015-07-21  1799  	/* enable link */
a9a9e4fd7 Thierry Reding     2015-04-27  1800  	value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
6b6b60421 Thierry Reding     2013-11-15  1801  	value |= SOR_DP_LINKCTL_ENABLE;
6b6b60421 Thierry Reding     2013-11-15  1802  	value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
a9a9e4fd7 Thierry Reding     2015-04-27  1803  	tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
6b6b60421 Thierry Reding     2013-11-15  1804  
6b6b60421 Thierry Reding     2013-11-15  1805  	for (i = 0, value = 0; i < 4; i++) {
6b6b60421 Thierry Reding     2013-11-15  1806  		unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
6b6b60421 Thierry Reding     2013-11-15  1807  				     SOR_DP_TPG_SCRAMBLER_GALIOS |
6b6b60421 Thierry Reding     2013-11-15  1808  				     SOR_DP_TPG_PATTERN_NONE;
6b6b60421 Thierry Reding     2013-11-15  1809  		value = (value << 8) | lane;
6b6b60421 Thierry Reding     2013-11-15  1810  	}
6b6b60421 Thierry Reding     2013-11-15  1811  
6b6b60421 Thierry Reding     2013-11-15  1812  	tegra_sor_writel(sor, value, SOR_DP_TPG);
6b6b60421 Thierry Reding     2013-11-15  1813  
6b6b60421 Thierry Reding     2013-11-15  1814  	/* enable pad calibration logic */
880cee0b7 Thierry Reding     2017-10-12  1815  	value = tegra_sor_readl(sor, sor->soc->regs->dp_padctl0);
6b6b60421 Thierry Reding     2013-11-15  1816  	value |= SOR_DP_PADCTL_PAD_CAL_PD;
880cee0b7 Thierry Reding     2017-10-12  1817  	tegra_sor_writel(sor, value, sor->soc->regs->dp_padctl0);
6b6b60421 Thierry Reding     2013-11-15  1818  
9542c2376 Thierry Reding     2015-07-08  1819  	err = drm_dp_link_probe(sor->aux, &link);
850bab448 Thierry Reding     2015-07-29  1820  	if (err < 0)
01b9bea0c Thierry Reding     2015-11-11  1821  		dev_err(sor->dev, "failed to probe eDP link: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1822  
9542c2376 Thierry Reding     2015-07-08  1823  	err = drm_dp_link_power_up(sor->aux, &link);
850bab448 Thierry Reding     2015-07-29  1824  	if (err < 0)
01b9bea0c Thierry Reding     2015-11-11  1825  		dev_err(sor->dev, "failed to power up eDP link: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1826  
9542c2376 Thierry Reding     2015-07-08  1827  	err = drm_dp_link_configure(sor->aux, &link);
850bab448 Thierry Reding     2015-07-29  1828  	if (err < 0)
01b9bea0c Thierry Reding     2015-11-11  1829  		dev_err(sor->dev, "failed to configure eDP link: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1830  
6b6b60421 Thierry Reding     2013-11-15  1831  	rate = drm_dp_link_rate_to_bw_code(link.rate);
6b6b60421 Thierry Reding     2013-11-15  1832  	lanes = link.num_lanes;
6b6b60421 Thierry Reding     2013-11-15  1833  
6b6b60421 Thierry Reding     2013-11-15  1834  	value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1835  	value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
6b6b60421 Thierry Reding     2013-11-15  1836  	value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate);
6b6b60421 Thierry Reding     2013-11-15  1837  	tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
6b6b60421 Thierry Reding     2013-11-15  1838  
a9a9e4fd7 Thierry Reding     2015-04-27  1839  	value = tegra_sor_readl(sor, SOR_DP_LINKCTL0);
6b6b60421 Thierry Reding     2013-11-15  1840  	value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
6b6b60421 Thierry Reding     2013-11-15  1841  	value |= SOR_DP_LINKCTL_LANE_COUNT(lanes);
6b6b60421 Thierry Reding     2013-11-15  1842  
6b6b60421 Thierry Reding     2013-11-15  1843  	if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
6b6b60421 Thierry Reding     2013-11-15  1844  		value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
6b6b60421 Thierry Reding     2013-11-15  1845  
a9a9e4fd7 Thierry Reding     2015-04-27  1846  	tegra_sor_writel(sor, value, SOR_DP_LINKCTL0);
6b6b60421 Thierry Reding     2013-11-15  1847  
6b6b60421 Thierry Reding     2013-11-15  1848  	/* disable training pattern generator */
6b6b60421 Thierry Reding     2013-11-15  1849  
6b6b60421 Thierry Reding     2013-11-15  1850  	for (i = 0; i < link.num_lanes; i++) {
6b6b60421 Thierry Reding     2013-11-15  1851  		unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
6b6b60421 Thierry Reding     2013-11-15  1852  				     SOR_DP_TPG_SCRAMBLER_GALIOS |
6b6b60421 Thierry Reding     2013-11-15  1853  				     SOR_DP_TPG_PATTERN_NONE;
6b6b60421 Thierry Reding     2013-11-15  1854  		value = (value << 8) | lane;
6b6b60421 Thierry Reding     2013-11-15  1855  	}
6b6b60421 Thierry Reding     2013-11-15  1856  
6b6b60421 Thierry Reding     2013-11-15  1857  	tegra_sor_writel(sor, value, SOR_DP_TPG);
6b6b60421 Thierry Reding     2013-11-15  1858  
6b6b60421 Thierry Reding     2013-11-15  1859  	err = tegra_sor_dp_train_fast(sor, &link);
01b9bea0c Thierry Reding     2015-11-11  1860  	if (err < 0)
01b9bea0c Thierry Reding     2015-11-11  1861  		dev_err(sor->dev, "DP fast link training failed: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1862  
6b6b60421 Thierry Reding     2013-11-15  1863  	dev_dbg(sor->dev, "fast link training succeeded\n");
6b6b60421 Thierry Reding     2013-11-15  1864  
6b6b60421 Thierry Reding     2013-11-15  1865  	err = tegra_sor_power_up(sor, 250);
850bab448 Thierry Reding     2015-07-29  1866  	if (err < 0)
6b6b60421 Thierry Reding     2013-11-15  1867  		dev_err(sor->dev, "failed to power up SOR: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1868  
6b6b60421 Thierry Reding     2013-11-15  1869  	/* CSTM (LVDS, link A/B, upper) */
143b1df23 Stéphane Marchesin 2014-05-22  1870  	value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_A | SOR_CSTM_LINK_ACT_B |
6b6b60421 Thierry Reding     2013-11-15  1871  		SOR_CSTM_UPPER;
6b6b60421 Thierry Reding     2013-11-15  1872  	tegra_sor_writel(sor, value, SOR_CSTM);
6b6b60421 Thierry Reding     2013-11-15  1873  
2bd1dd399 Thierry Reding     2015-08-03  1874  	/* use DP-A protocol */
2bd1dd399 Thierry Reding     2015-08-03  1875  	value = tegra_sor_readl(sor, SOR_STATE1);
2bd1dd399 Thierry Reding     2015-08-03  1876  	value &= ~SOR_STATE_ASY_PROTOCOL_MASK;
2bd1dd399 Thierry Reding     2015-08-03  1877  	value |= SOR_STATE_ASY_PROTOCOL_DP_A;
2bd1dd399 Thierry Reding     2015-08-03  1878  	tegra_sor_writel(sor, value, SOR_STATE1);
2bd1dd399 Thierry Reding     2015-08-03  1879  
c31efa7a3 Thierry Reding     2015-09-08  1880  	tegra_sor_mode_set(sor, mode, state);
2bd1dd399 Thierry Reding     2015-08-03  1881  
6fad8f66d Thierry Reding     2014-11-28  1882  	/* PWM setup */
6fad8f66d Thierry Reding     2014-11-28  1883  	err = tegra_sor_setup_pwm(sor, 250);
850bab448 Thierry Reding     2015-07-29  1884  	if (err < 0)
6fad8f66d Thierry Reding     2014-11-28  1885  		dev_err(sor->dev, "failed to setup PWM: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1886  
666cb8733 Thierry Reding     2014-12-08  1887  	tegra_sor_update(sor);
666cb8733 Thierry Reding     2014-12-08  1888  
6fad8f66d Thierry Reding     2014-11-28  1889  	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
c57997bce Thierry Reding     2017-10-12  1890  	value |= SOR_ENABLE(0);
6fad8f66d Thierry Reding     2014-11-28  1891  	tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
6b6b60421 Thierry Reding     2013-11-15  1892  
666cb8733 Thierry Reding     2014-12-08  1893  	tegra_dc_commit(dc);
6b6b60421 Thierry Reding     2013-11-15  1894  
6fad8f66d Thierry Reding     2014-11-28  1895  	err = tegra_sor_attach(sor);
850bab448 Thierry Reding     2015-07-29  1896  	if (err < 0)
6fad8f66d Thierry Reding     2014-11-28  1897  		dev_err(sor->dev, "failed to attach SOR: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1898  
6fad8f66d Thierry Reding     2014-11-28  1899  	err = tegra_sor_wakeup(sor);
850bab448 Thierry Reding     2015-07-29  1900  	if (err < 0)
6fad8f66d Thierry Reding     2014-11-28  1901  		dev_err(sor->dev, "failed to enable DC: %d\n", err);
6b6b60421 Thierry Reding     2013-11-15  1902  
6fad8f66d Thierry Reding     2014-11-28  1903  	if (output->panel)
6fad8f66d Thierry Reding     2014-11-28  1904  		drm_panel_enable(output->panel);
a82752e19 Thierry Reding     2014-01-31  1905  }
a82752e19 Thierry Reding     2014-01-31  1906  

:::::: The code at line 1550 was first introduced by commit
:::::: c57997bce423fb71334a1fefa524569e48a1718f drm/tegra: sor: Add Tegra186 support

:::::: TO: Thierry Reding <treding@nvidia.com>
:::::: CC: Thierry Reding <treding@nvidia.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox series

Patch

diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index 2d6f3fc..af69f42 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -33,6 +33,9 @@ 
 #include <linux/of_address.h>
 #include <linux/of_clk.h>
 #include <linux/of_platform.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
 #include <linux/reboot.h>
@@ -45,6 +48,8 @@ 
 #include <soc/tegra/fuse.h>
 #include <soc/tegra/pmc.h>
 
+#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
+
 #define PMC_CNTRL			0x0
 #define  PMC_CNTRL_INTR_POLARITY	BIT(17) /* inverts INTR polarity */
 #define  PMC_CNTRL_CPU_PWRREQ_OE	BIT(16) /* CPU pwr req enable */
@@ -118,6 +123,17 @@ 
 
 #define GPU_RG_CNTRL			0x2d4
 
+#define TEGRA_PMC_SEL_DPD_TIM		0x1c8
+#define TEGRA_PMC_IO_DPD_SAMPLE		0x20
+#define TEGRA_PMC_PWR_DET_ENABLE	0x48
+#define TEGRA_PMC_PWR_DET_VAL		0xe4
+#define TEGRA_PMC_IO_DPD_REQ		0x74
+#define TEGRA_PMC_IO_DPD_STATUS		0x78
+#define TEGRA_PMC_IO_DPD2_REQ		0x7C
+#define TEGRA_PMC_IO_DPD2_STATUS	0x80
+#define TEGRA_PMC_E_18V_PWR		0x3C
+#define TEGRA_PMC_E_33V_PWR		0x40
+
 /* Tegra186 and later */
 #define WAKE_AOWAKE_CTRL 0x4f4
 #define  WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0)
@@ -132,9 +148,21 @@  struct tegra_powergate {
 };
 
 struct tegra_io_pad_soc {
-	enum tegra_io_pad id;
+	const char *name;
+	const unsigned int pins[1];
+	unsigned int npins;
 	unsigned int dpd;
 	unsigned int voltage;
+	unsigned int io_power;
+	unsigned int dpd_req_reg;
+	unsigned int dpd_status_reg;
+	unsigned int dpd_timer_reg;
+	unsigned int dpd_sample_reg;
+	unsigned int pwr_det_enable_reg;
+	unsigned int pwr_det_val_reg;
+	unsigned int pad_uv_0;
+	unsigned int pad_uv_1;
+	bool bdsdmem_cfc;
 };
 
 struct tegra_pmc_regs {
@@ -157,6 +185,8 @@  struct tegra_pmc_soc {
 
 	const struct tegra_io_pad_soc *io_pads;
 	unsigned int num_io_pads;
+	const struct pinctrl_pin_desc *descs;
+	unsigned int num_descs;
 
 	const struct tegra_pmc_regs *regs;
 	void (*init)(struct tegra_pmc *pmc);
@@ -187,6 +217,10 @@  struct tegra_pmc_soc {
  * @lp0_vec_size: size of the LP0 warm boot code
  * @powergates_available: Bitmap of available power gates
  * @powergates_lock: mutex for power gate register access
+ * @pctl: pinctrl handle which is returned after registering pinctrl
+ * @pinctrl_desc: Pincontrol descriptor for IO pads
+ * @allow_dynamic_switch: restrict the voltage change for each io pad
+ * @voltage_switch_restriction_enabled: restrict voltage switch for all io pads
  */
 struct tegra_pmc {
 	struct device *dev;
@@ -216,6 +250,15 @@  struct tegra_pmc {
 	DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX);
 
 	struct mutex powergates_lock;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_desc pinctrl_desc;
+	bool *allow_dynamic_switch;
+	bool voltage_switch_restriction_enabled;
+};
+
+static const char * const tegra_sor_pad_names[] = {
+	[TEGRA_IO_RAIL_HDMI] = "hdmi",
+	[TEGRA_IO_RAIL_LVDS] = "lvds",
 };
 
 static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -907,70 +950,42 @@  static void tegra_powergate_init(struct tegra_pmc *pmc,
 	of_node_put(np);
 }
 
-static const struct tegra_io_pad_soc *
-tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
-{
-	unsigned int i;
-
-	for (i = 0; i < pmc->soc->num_io_pads; i++)
-		if (pmc->soc->io_pads[i].id == id)
-			return &pmc->soc->io_pads[i];
-
-	return NULL;
-}
-
-static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request,
-				unsigned long *status, u32 *mask)
+static int tegra_io_pad_prepare(const struct tegra_io_pad_soc *pad)
 {
-	const struct tegra_io_pad_soc *pad;
 	unsigned long rate, value;
 
-	pad = tegra_io_pad_find(pmc, id);
-	if (!pad) {
-		pr_err("invalid I/O pad ID %u\n", id);
-		return -ENOENT;
-	}
-
 	if (pad->dpd == UINT_MAX)
 		return -ENOTSUPP;
 
-	*mask = BIT(pad->dpd % 32);
+	if (!pmc->clk)
+		return 0;
 
-	if (pad->dpd < 32) {
-		*status = pmc->soc->regs->dpd_status;
-		*request = pmc->soc->regs->dpd_req;
-	} else {
-		*status = pmc->soc->regs->dpd2_status;
-		*request = pmc->soc->regs->dpd2_req;
+	rate = clk_get_rate(pmc->clk);
+	if (!rate) {
+		dev_err(pmc->dev, "Failed to get clock rate\n");
+		return -ENODEV;
 	}
 
-	if (pmc->clk) {
-		rate = clk_get_rate(pmc->clk);
-		if (!rate) {
-			pr_err("failed to get clock rate\n");
-			return -ENODEV;
-		}
+	tegra_pmc_writel(DPD_SAMPLE_ENABLE, pad->dpd_sample_reg);
 
-		tegra_pmc_writel(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);
-		tegra_pmc_writel(value, SEL_DPD_TIM);
-	}
+	/* must be at least 200 ns, in APB (PCLK) clock cycles */
+	value = DIV_ROUND_UP(1000000000, rate);
+	value = DIV_ROUND_UP(200, value);
+	tegra_pmc_writel(value, pad->dpd_timer_reg);
 
 	return 0;
 }
 
-static int tegra_io_pad_poll(unsigned long offset, u32 mask,
+static int tegra_io_pad_poll(const struct tegra_io_pad_soc *pad,
 			     u32 val, unsigned long timeout)
 {
 	u32 value;
+	u32 mask = BIT(pad->dpd);
 
 	timeout = jiffies + msecs_to_jiffies(timeout);
 
 	while (time_after(timeout, jiffies)) {
-		value = tegra_pmc_readl(offset);
+		value = tegra_pmc_readl(pad->dpd_status_reg);
 		if ((value & mask) == val)
 			return 0;
 
@@ -980,10 +995,22 @@  static int tegra_io_pad_poll(unsigned long offset, u32 mask,
 	return -ETIMEDOUT;
 }
 
-static void tegra_io_pad_unprepare(void)
+static void tegra_io_pad_unprepare(const struct tegra_io_pad_soc *pad)
 {
 	if (pmc->clk)
-		tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
+		tegra_pmc_writel(DPD_SAMPLE_DISABLE,  pad->dpd_sample_reg);
+}
+
+static const struct tegra_io_pad_soc *tegra_get_pad_by_name(const char *pname)
+{
+	unsigned int i;
+
+	for (i = 0; i < pmc->soc->num_io_pads; ++i) {
+		if (!strcmp(pname, pmc->soc->io_pads[i].name))
+			return &pmc->soc->io_pads[i];
+	}
+
+	return NULL;
 }
 
 /**
@@ -992,35 +1019,33 @@  static void tegra_io_pad_unprepare(void)
  *
  * Returns: 0 on success or a negative error code on failure.
  */
-int tegra_io_pad_power_enable(enum tegra_io_pad id)
+static int tegra_io_pad_power_enable(const struct tegra_io_pad_soc *pad)
 {
-	unsigned long request, status;
-	u32 mask;
 	int err;
 
 	mutex_lock(&pmc->powergates_lock);
 
-	err = tegra_io_pad_prepare(id, &request, &status, &mask);
+	err = tegra_io_pad_prepare(pad);
 	if (err < 0) {
-		pr_err("failed to prepare I/O pad: %d\n", err);
+		pr_err("failed to prepare I/O pad %s: %d\n", pad->name, err);
 		goto unlock;
 	}
 
-	tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | mask, request);
+	tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(pad->dpd),
+			 pad->dpd_req_reg);
 
-	err = tegra_io_pad_poll(status, mask, 0, 250);
+	err = tegra_io_pad_poll(pad, 0, 250);
 	if (err < 0) {
-		pr_err("failed to enable I/O pad: %d\n", err);
+		pr_err("failed to enable I/O pad %s: %d\n", pad->name, err);
 		goto unlock;
 	}
 
-	tegra_io_pad_unprepare();
+	tegra_io_pad_unprepare(pad);
 
 unlock:
 	mutex_unlock(&pmc->powergates_lock);
 	return err;
 }
-EXPORT_SYMBOL(tegra_io_pad_power_enable);
 
 /**
  * tegra_io_pad_power_disable() - disable power to I/O pad
@@ -1028,65 +1053,63 @@  EXPORT_SYMBOL(tegra_io_pad_power_enable);
  *
  * Returns: 0 on success or a negative error code on failure.
  */
-int tegra_io_pad_power_disable(enum tegra_io_pad id)
+static int tegra_io_pad_power_disable(const struct tegra_io_pad_soc *pad)
 {
-	unsigned long request, status;
-	u32 mask;
 	int err;
 
 	mutex_lock(&pmc->powergates_lock);
 
-	err = tegra_io_pad_prepare(id, &request, &status, &mask);
+	err = tegra_io_pad_prepare(pad);
 	if (err < 0) {
-		pr_err("failed to prepare I/O pad: %d\n", err);
+		pr_err("failed to prepare I/O pad %s: %d\n", pad->name, err);
 		goto unlock;
 	}
 
-	tegra_pmc_writel(IO_DPD_REQ_CODE_ON | mask, request);
+	tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(pad->dpd),
+			 pad->dpd_req_reg);
 
-	err = tegra_io_pad_poll(status, mask, mask, 250);
+	err = tegra_io_pad_poll(pad, BIT(pad->dpd), 250);
 	if (err < 0) {
-		pr_err("failed to disable I/O pad: %d\n", err);
+		pr_err("failed to disable I/O pad %s: %d\n", pad->name, err);
 		goto unlock;
 	}
 
-	tegra_io_pad_unprepare();
+	tegra_io_pad_unprepare(pad);
 
 unlock:
 	mutex_unlock(&pmc->powergates_lock);
 	return err;
 }
-EXPORT_SYMBOL(tegra_io_pad_power_disable);
 
-int tegra_io_pad_set_voltage(enum tegra_io_pad id,
-			     enum tegra_io_pad_voltage voltage)
+static int tegra_io_pad_set_voltage(const struct tegra_io_pad_soc *pad,
+				    int io_pad_uv)
 {
-	const struct tegra_io_pad_soc *pad;
 	u32 value;
 
-	pad = tegra_io_pad_find(pmc, id);
-	if (!pad)
-		return -ENOENT;
-
 	if (pad->voltage == UINT_MAX)
 		return -ENOTSUPP;
 
+	if (io_pad_uv != pad->pad_uv_0 && io_pad_uv != pad->pad_uv_1)
+		return -EINVAL;
+
 	mutex_lock(&pmc->powergates_lock);
 
 	/* write-enable PMC_PWR_DET_VALUE[pad->voltage] */
-	value = tegra_pmc_readl(PMC_PWR_DET);
-	value |= BIT(pad->voltage);
-	tegra_pmc_writel(value, PMC_PWR_DET);
+	if (pad->pwr_det_enable_reg != UINT_MAX) {
+		value = tegra_pmc_readl(pad->pwr_det_enable_reg);
+		value |= BIT(pad->voltage);
+		tegra_pmc_writel(value, pad->pwr_det_enable_reg);
+	}
 
 	/* update I/O voltage */
-	value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
+	value = tegra_pmc_readl(pad->pwr_det_val_reg);
 
-	if (voltage == TEGRA_IO_PAD_1800000UV)
+	if (io_pad_uv == pad->pad_uv_0)
 		value &= ~BIT(pad->voltage);
 	else
 		value |= BIT(pad->voltage);
 
-	tegra_pmc_writel(value, PMC_PWR_DET_VALUE);
+	tegra_pmc_writel(value, pad->pwr_det_val_reg);
 
 	mutex_unlock(&pmc->powergates_lock);
 
@@ -1094,28 +1117,289 @@  int tegra_io_pad_set_voltage(enum tegra_io_pad id,
 
 	return 0;
 }
-EXPORT_SYMBOL(tegra_io_pad_set_voltage);
 
-int tegra_io_pad_get_voltage(enum tegra_io_pad id)
+static int tegra_io_pad_get_voltage(const struct tegra_io_pad_soc *pad)
 {
-	const struct tegra_io_pad_soc *pad;
 	u32 value;
 
-	pad = tegra_io_pad_find(pmc, id);
-	if (!pad)
-		return -ENOENT;
-
 	if (pad->voltage == UINT_MAX)
 		return -ENOTSUPP;
 
-	value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
+	value = tegra_pmc_readl(pad->pwr_det_val_reg);
 
 	if ((value & BIT(pad->voltage)) == 0)
-		return TEGRA_IO_PAD_1800000UV;
+		return pad->pad_uv_0;
 
-	return TEGRA_IO_PAD_3300000UV;
+	return pad->pad_uv_1;
+}
+
+/**
+ * tegra_io_pad_is_powered() - check if IO pad is powered
+ * @pad: Tegra I/O pad SOC data for which power status need to check
+ *
+ * Return 1 if power-ON, 0 if power OFF and error number in
+ * negative if pad ID is not valid or power down not supported
+ * on given IO pad.
+ */
+static int tegra_io_pad_is_powered(const struct tegra_io_pad_soc *pad)
+{
+	u32 value;
+
+	if (pad->dpd == UINT_MAX)
+		return -ENOTSUPP;
+
+	value = tegra_pmc_readl(pad->dpd_status_reg);
+
+	return !(value & BIT(pad->dpd));
+}
+
+static int tegra_io_pads_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct tegra_pmc *tpmc = pinctrl_dev_get_drvdata(pctldev);
+
+	return tpmc->soc->num_io_pads;
+}
+
+static const char *tegra_io_pads_pinctrl_get_group_name(
+			struct pinctrl_dev *pctldev, unsigned int group)
+{
+	struct tegra_pmc *tpmc = pinctrl_dev_get_drvdata(pctldev);
+
+	return tpmc->soc->io_pads[group].name;
+}
+
+static int tegra_io_pads_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+						unsigned int group,
+						const unsigned int **pins,
+						unsigned int *num_pins)
+{
+	struct tegra_pmc *tpmc = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = tpmc->soc->io_pads[group].pins;
+	*num_pins = tpmc->soc->io_pads[group].npins;
+
+	return 0;
+}
+
+enum tegra_io_rail_pads_params {
+	TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE = PIN_CONFIG_END + 1,
+	TEGRA_IO_PAD_DYNAMIC_VOLTAGE_SWITCH = PIN_CONFIG_END + 2,
+};
+
+static const struct pinconf_generic_params tegra_io_pads_cfg_params[] = {
+	{
+		.property = "nvidia,power-source-voltage",
+		.param = TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE,
+	}, {
+		.property = "nvidia,enable-voltage-switching",
+		.param = TEGRA_IO_PAD_DYNAMIC_VOLTAGE_SWITCH,
+	},
+};
+
+static const struct pinctrl_ops tegra_io_pads_pinctrl_ops = {
+	.get_groups_count = tegra_io_pads_pinctrl_get_groups_count,
+	.get_group_name	= tegra_io_pads_pinctrl_get_group_name,
+	.get_group_pins	= tegra_io_pads_pinctrl_get_group_pins,
+	.dt_node_to_map	= pinconf_generic_dt_node_to_map_pin,
+	.dt_free_map	= pinconf_generic_dt_free_map,
+};
+
+static int tegra_io_pads_pinconf_get(struct pinctrl_dev *pctldev,
+				     unsigned int pin,
+				     unsigned long *config)
+{
+	struct tegra_pmc *tpmc = pinctrl_dev_get_drvdata(pctldev);
+	u16 param = pinconf_to_config_param(*config);
+	const struct tegra_io_pad_soc *pad = &tpmc->soc->io_pads[pin];
+	u16 arg = 0;
+	int ret;
+
+	switch (param) {
+	case PIN_CONFIG_LOW_POWER_MODE:
+		ret = tegra_io_pad_is_powered(pad);
+		if (ret < 0)
+			return ret;
+		arg = !ret;
+		break;
+	case TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE:
+		if (pmc->soc->io_pads[pin].voltage == UINT_MAX)
+			return -EINVAL;
+
+		ret = tegra_io_pad_get_voltage(pad);
+		if (ret < 0)
+			return ret;
+		arg = ret;
+		break;
+	case TEGRA_IO_PAD_DYNAMIC_VOLTAGE_SWITCH:
+		if (pmc->soc->io_pads[pin].voltage == UINT_MAX)
+			return -EINVAL;
+
+		if (pmc->voltage_switch_restriction_enabled &&
+		    pmc->allow_dynamic_switch[pin])
+			arg = 1;
+		else
+			arg = 0;
+		break;
+	default:
+		dev_dbg(tpmc->dev, "I/O pad %s does not support param %d\n",
+			pad->name, param);
+		return -EINVAL;
+	}
+
+	*config = pinconf_to_config_packed(param, arg);
+
+	return 0;
+}
+
+static int tegra_io_pads_pinconf_set(struct pinctrl_dev *pctldev,
+				     unsigned int pin, unsigned long *configs,
+				     unsigned int num_configs)
+{
+	struct tegra_pmc *tpmc = pinctrl_dev_get_drvdata(pctldev);
+	const struct tegra_io_pad_soc *pad = &tpmc->soc->io_pads[pin];
+	unsigned int i;
+	int ret;
+
+	for (i = 0; i < num_configs; i++) {
+		u16 param_val = pinconf_to_config_argument(configs[i]);
+		u16 param = pinconf_to_config_param(configs[i]);
+
+		switch (param) {
+		case PIN_CONFIG_LOW_POWER_MODE:
+			if (param_val)
+				ret = tegra_io_pad_power_disable(pad);
+			else
+				ret = tegra_io_pad_power_enable(pad);
+			if (ret < 0) {
+				dev_err(tpmc->dev,
+					"Failed to set low power %s of I/O pad %s: %d\n",
+					(param_val) ? "disable" : "enable",
+					pad->name, ret);
+				return ret;
+			}
+			break;
+		case TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE:
+			if (pmc->soc->io_pads[pin].voltage == UINT_MAX)
+				return -EINVAL;
+
+			if (pmc->voltage_switch_restriction_enabled &&
+			    !pmc->allow_dynamic_switch[pin]) {
+				dev_err(tpmc->dev,
+					"IO Pad %s: Dynamic voltage switching not allowed\n",
+					pad->name);
+				return -EINVAL;
+			}
+
+			ret = tegra_io_pad_set_voltage(pad, param_val);
+			if (ret < 0) {
+				dev_err(tpmc->dev,
+					"Failed to set voltage %d of pin %u: %d\n",
+					param_val, pin, ret);
+				return ret;
+			}
+			break;
+		case TEGRA_IO_PAD_DYNAMIC_VOLTAGE_SWITCH:
+			if (pmc->soc->io_pads[pin].voltage == UINT_MAX)
+				return -EINVAL;
+
+			pmc->allow_dynamic_switch[pin] = true;
+			break;
+		default:
+			dev_err(tpmc->dev, "I/O pad %s does not support param %d\n",
+				pad->name, param);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void tegra_io_pads_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+					   struct seq_file *s, unsigned int pin)
+{
+	struct tegra_pmc *tpmc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned long config = 0;
+	u16 param, param_val;
+	int ret;
+	int i;
+
+	for (i = 0; i < tpmc->pinctrl_desc.num_custom_params; ++i) {
+		param = tpmc->pinctrl_desc.custom_params[i].param;
+		config = pinconf_to_config_packed(param, 0);
+		ret = tegra_io_pads_pinconf_get(pctldev, pin, &config);
+		if (ret < 0)
+			continue;
+		param_val = pinconf_to_config_argument(config);
+		switch (param) {
+		case TEGRA_IO_PAD_POWER_SOURCE_VOLTAGE:
+			if (param_val == TEGRA_IO_PAD_VOLTAGE_1200000UV)
+				seq_puts(s, "\n\t\tPad voltage 1200000uV");
+			else if (param_val == TEGRA_IO_PAD_VOLTAGE_1800000UV)
+				seq_puts(s, "\n\t\tPad voltage 1800000uV");
+			else
+				seq_puts(s, "\n\t\tPad voltage 3300000uV");
+			break;
+		case TEGRA_IO_PAD_DYNAMIC_VOLTAGE_SWITCH:
+			seq_printf(s, "\n\t\tSwitching voltage: %s",
+				   (param_val) ? "Enable" : "Disable");
+			break;
+		default:
+			break;
+		}
+	}
+}
+#else
+static void tegra_io_pads_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+					   struct seq_file *s, unsigned int pin)
+{
+}
+#endif
+
+static const struct pinconf_ops tegra_io_pads_pinconf_ops = {
+	.pin_config_get = tegra_io_pads_pinconf_get,
+	.pin_config_set = tegra_io_pads_pinconf_set,
+	.pin_config_dbg_show = tegra_io_pads_pinconf_dbg_show,
+	.is_generic = true,
+};
+
+static int tegra_io_pads_pinctrl_init(struct tegra_pmc *pmc)
+{
+	if (!pmc->soc->num_descs)
+		return 0;
+
+	pmc->allow_dynamic_switch = devm_kzalloc(pmc->dev, pmc->soc->num_descs *
+					 sizeof(*pmc->allow_dynamic_switch),
+					 GFP_KERNEL);
+	if (!pmc->allow_dynamic_switch) {
+		pr_err("failed to allocate allow_dynamic_switch\n");
+		return 0;
+	}
+
+	pmc->voltage_switch_restriction_enabled = false;
+	pmc->pinctrl_desc.name = "pinctrl-pmc-io-pads";
+	pmc->pinctrl_desc.pctlops = &tegra_io_pads_pinctrl_ops;
+	pmc->pinctrl_desc.confops = &tegra_io_pads_pinconf_ops;
+	pmc->pinctrl_desc.pins = pmc->soc->descs;
+	pmc->pinctrl_desc.npins = pmc->soc->num_descs;
+	pmc->pinctrl_desc.custom_params = tegra_io_pads_cfg_params;
+	pmc->pinctrl_desc.num_custom_params =
+				ARRAY_SIZE(tegra_io_pads_cfg_params);
+
+	pmc->pctl = devm_pinctrl_register(pmc->dev, &pmc->pinctrl_desc, pmc);
+	if (IS_ERR(pmc->pctl)) {
+		int ret = PTR_ERR(pmc->pctl);
+
+		pr_err("failed to register pinctrl-io-pad: %d\n", ret);
+		return ret;
+	}
+
+	pmc->voltage_switch_restriction_enabled =
+		of_property_read_bool(pmc->dev->of_node,
+				      "nvidia,restrict-voltage-switch");
+
+	return 0;
 }
-EXPORT_SYMBOL(tegra_io_pad_get_voltage);
 
 /**
  * tegra_io_rail_power_on() - enable power to I/O rail
@@ -1125,7 +1409,20 @@  EXPORT_SYMBOL(tegra_io_pad_get_voltage);
  */
 int tegra_io_rail_power_on(unsigned int id)
 {
-	return tegra_io_pad_power_enable(id);
+	const struct tegra_io_pad_soc *pad;
+
+	if (id != TEGRA_IO_RAIL_LVDS && id != TEGRA_IO_RAIL_HDMI) {
+		dev_err(pmc->dev, "invalid pad id\n");
+		return -EINVAL;
+	}
+
+	pad = tegra_get_pad_by_name(tegra_sor_pad_names[id]);
+	if (!pad) {
+		dev_err(pmc->dev, "IO Pad not found\n");
+		return -EINVAL;
+	}
+
+	return tegra_io_pad_power_enable(pad);
 }
 EXPORT_SYMBOL(tegra_io_rail_power_on);
 
@@ -1137,7 +1434,20 @@  EXPORT_SYMBOL(tegra_io_rail_power_on);
  */
 int tegra_io_rail_power_off(unsigned int id)
 {
-	return tegra_io_pad_power_disable(id);
+	const struct tegra_io_pad_soc *pad;
+
+	if (id != TEGRA_IO_RAIL_LVDS && id != TEGRA_IO_RAIL_HDMI) {
+		dev_err(pmc->dev, "invalid pad id\n");
+		return -EINVAL;
+	}
+
+	pad = tegra_get_pad_by_name(tegra_sor_pad_names[id]);
+	if (!pad) {
+		dev_err(pmc->dev, "IO Pad not found\n");
+		return -EINVAL;
+	}
+
+	return tegra_io_pad_power_disable(pad);
 }
 EXPORT_SYMBOL(tegra_io_rail_power_off);
 
@@ -1436,6 +1746,10 @@  static int tegra_pmc_probe(struct platform_device *pdev)
 		return err;
 	}
 
+	err = tegra_io_pads_pinctrl_init(pmc);
+	if (err < 0)
+		return err;
+
 	mutex_lock(&pmc->powergates_lock);
 	iounmap(pmc->base);
 	pmc->base = base;
@@ -1649,37 +1963,77 @@  static const u8 tegra124_cpu_powergates[] = {
 	TEGRA_POWERGATE_CPU3,
 };
 
+#define TEGRA124_IO_PAD_CONFIG(_pin, _npins, _name, _dpd,	\
+			       _vbit, _iopower, _reg)		\
+	{							\
+		.name =  #_name,				\
+		.pins = {(_pin)},				\
+		.npins = _npins,				\
+		.dpd = _dpd,					\
+		.voltage = _vbit,				\
+		.io_power = _iopower,				\
+		.dpd_req_reg = TEGRA_PMC_IO_##_reg##_REQ,	\
+		.dpd_status_reg = TEGRA_PMC_IO_##_reg##_STATUS,	\
+		.dpd_timer_reg = TEGRA_PMC_SEL_DPD_TIM,		\
+		.dpd_sample_reg = TEGRA_PMC_IO_DPD_SAMPLE,	\
+		.pwr_det_enable_reg = TEGRA_PMC_PWR_DET_ENABLE, \
+		.pwr_det_val_reg = TEGRA_PMC_PWR_DET_VAL, \
+	},
+
+/**
+ * All IO pads of Tegra SoCs do not support the low power and multi level
+ * voltage configurations for its pads.
+ * Defining macros for different cases as follows:
+ * TEGRA_IO_PAD_LPONLY : IO pad which support low power state but
+ *			 operate in single level of IO voltage.
+ */
+#define TEGRA124_IO_PAD_LPONLY(_pin, _name, _dpd, _reg)	\
+	TEGRA124_IO_PAD_CONFIG(_pin, 1, _name, _dpd, UINT_MAX, UINT_MAX, _reg)
+
+#define TEGRA124_IO_PAD_DESC_LP(_pin, _name, _dpd, _reg)	\
+	{					\
+		.number = _pin,			\
+		.name = #_name,			\
+	},
+
+#define TEGRA124_IO_PAD_TABLE(_lponly_, _pvonly_, _lp_n_pv_)	\
+	_lponly_(0, audio, 17, DPD)			\
+	_lponly_(1, bb, 15, DPD)			\
+	_lponly_(2, cam, 4, DPD2)			\
+	_lponly_(3, comp, 22, DPD)			\
+	_lponly_(4, csia, 0, DPD2)			\
+	_lponly_(5, csib, 1, DPD2)			\
+	_lponly_(6, csie, 12, DPD2)			\
+	_lponly_(7, dp, 19, DPD2)			\
+	_lponly_(8, dsi, 2, DPD)			\
+	_lponly_(9, dsib, 7, DPD2)			\
+	_lponly_(10, dsic, 8, DPD2)			\
+	_lponly_(11, dsid, 9, DPD2)			\
+	_lponly_(12, hdmi, 28, DPD)			\
+	_lponly_(13, hsic, 19, DPD)			\
+	_lponly_(14, lvds, 25, DPD2)			\
+	_lponly_(15, mipi-bias, 3, DPD)			\
+	_lponly_(16, nand, 13, DPD)			\
+	_lponly_(17, pex-bias, 4, DPD)			\
+	_lponly_(18, pex-clk1, 5, DPD)			\
+	_lponly_(19, pex-clk2, 6, DPD)			\
+	_lponly_(20, pex-ctrl, 0, DPD2)			\
+	_lponly_(21, sdmmc1, 1, DPD2)		\
+	_lponly_(22, sdmmc3, 2, DPD2)		\
+	_lponly_(23, sdmmc4, 3, DPD2)		\
+	_lponly_(24, sys-ddc, 26, DPD)		\
+	_lponly_(25, uart, 14, DPD)		\
+	_lponly_(26, usb0, 9, DPD)			\
+	_lponly_(27, usb1, 10, DPD)			\
+	_lponly_(28, usb2, 11, DPD)			\
+	_lponly_(29, usb-bias, 12, DPD)			\
+
 static const struct tegra_io_pad_soc tegra124_io_pads[] = {
-	{ .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_BB, .dpd = 15, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_COMP, .dpd = 22, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_HV, .dpd = 38, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_NAND, .dpd = 13, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SDMMC4, .dpd = 35, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SYS_DDC, .dpd = 58, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
+	TEGRA124_IO_PAD_TABLE(TEGRA124_IO_PAD_LPONLY, NULL, NULL)
+};
+
+static const struct pinctrl_pin_desc tegra124_io_pads_pinctrl_desc[] = {
+	TEGRA124_IO_PAD_TABLE(TEGRA124_IO_PAD_DESC_LP, NULL, NULL)
 };
 
 static const struct tegra_pmc_soc tegra124_pmc_soc = {
@@ -1694,6 +2048,8 @@  static const struct tegra_pmc_soc tegra124_pmc_soc = {
 	.regs = &tegra20_pmc_regs,
 	.init = tegra20_pmc_init,
 	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
+	.num_descs = ARRAY_SIZE(tegra124_io_pads_pinctrl_desc),
+	.descs = tegra124_io_pads_pinctrl_desc,
 };
 
 static const char * const tegra210_powergates[] = {
@@ -1730,45 +2086,111 @@  static const u8 tegra210_cpu_powergates[] = {
 	TEGRA_POWERGATE_CPU3,
 };
 
+#define TEGRA210X_IO_PAD_CONFIG(_pin, _npins, _name, _dpd,	\
+			       _vbit, _iopower, _reg, _bds)	\
+	{							\
+		.name =  #_name,				\
+		.pins = {(_pin)},				\
+		.npins = _npins,				\
+		.dpd = _dpd,					\
+		.voltage = _vbit,				\
+		.io_power = _iopower,				\
+		.dpd_req_reg = TEGRA_PMC_IO_##_reg##_REQ,	\
+		.dpd_status_reg = TEGRA_PMC_IO_##_reg##_STATUS,	\
+		.dpd_timer_reg = TEGRA_PMC_SEL_DPD_TIM,		\
+		.dpd_sample_reg = TEGRA_PMC_IO_DPD_SAMPLE,	\
+		.bdsdmem_cfc = _bds,				\
+		.pwr_det_enable_reg = TEGRA_PMC_PWR_DET_ENABLE, \
+		.pwr_det_val_reg = TEGRA_PMC_PWR_DET_VAL, \
+		.pad_uv_0 = TEGRA_IO_PAD_VOLTAGE_1800000UV,	\
+		.pad_uv_1 = TEGRA_IO_PAD_VOLTAGE_3300000UV,	\
+	},
+
+#define TEGRA210_IO_PAD_CONFIG(_pin, _npins, _name, _dpd,	\
+			       _vbit, _iopower, _reg)		\
+	TEGRA210X_IO_PAD_CONFIG(_pin, _npins, _name, _dpd,	\
+				_vbit, _iopower, _reg, false)
+
+/**
+ * All IO pads of Tegra SoCs do not support the low power and multi level
+ * voltage configurations for its pads.
+ * Defining macros for different cases as follows:
+ * TEGRA_IO_PAD_LPONLY : IO pad which support low power state but
+ *			 operate in single level of IO voltage.
+ * TEGRA_IO_PAD_LP_N_PV: IO pad which support low power state as well as
+ *			 it can operate in multi-level voltages.
+ * TEGRA_IO_PAD_PVONLY:  IO pad which does not support low power state but
+ *			 it can operate in multi-level voltages.
+ */
+#define TEGRA210_IO_PAD_LPONLY(_pin, _name, _dpd, _reg)	\
+	TEGRA210_IO_PAD_CONFIG(_pin, 1, _name, _dpd, UINT_MAX, UINT_MAX, _reg)
+
+#define TEGRA210_IO_PAD_LP_N_PV(_pin, _name, _dpd, _vbit, _io, _reg)  \
+	TEGRA210_IO_PAD_CONFIG(_pin, 1, _name, _dpd, _vbit, _io, _reg)
+
+#define TEGRA210_IO_PAD_PVONLY(_pin, _name, _vbit, _io, _reg)	\
+	TEGRA210_IO_PAD_CONFIG(_pin, 0, _name, UINT_MAX, _vbit, _io, _reg)
+
+#define TEGRA210_IO_PAD_DESC_LP(_pin, _name, _dpd, _reg)	\
+	{					\
+		.number = _pin,			\
+		.name = #_name,			\
+	},
+#define TEGRA210_IO_PAD_DESC_LP_N_PV(_pin, _name, _dpd, _vbit, _io, _reg) \
+	TEGRA210_IO_PAD_DESC_LP(_pin, _name, _dpd, _reg)
+
+#define TEGRA210_IO_PAD_DESC_PV(_pin, _name, _vbit, _io, _reg) \
+	TEGRA210_IO_PAD_DESC_LP(_pin, _name, UINT_MAX, _reg)
+
+#define TEGRA210_IO_PAD_TABLE(_lponly_, _pvonly_, _lp_n_pv_)	\
+	_lp_n_pv_(0, audio, 17, 5, 5, DPD)		\
+	_lp_n_pv_(1, audio-hv, 29, 18, 18, DPD2)	\
+	_lp_n_pv_(2, cam, 4, 10, 10, DPD2)		\
+	_lponly_(3, csia, 0, DPD)			\
+	_lponly_(4, csib, 1, DPD)			\
+	_lponly_(5, csic, 10, DPD2)			\
+	_lponly_(6, csid, 11, DPD2)			\
+	_lponly_(7, csie, 12, DPD2)			\
+	_lponly_(8, csif, 13, DPD2)			\
+	_lp_n_pv_(9, dbg, 25, 19, 19, DPD)		\
+	_lponly_(10, debug-nonao, 26, DPD)		\
+	_lp_n_pv_(11, dmic, 18, 20, 20, DPD2)		\
+	_lponly_(12, dp, 19, DPD2)			\
+	_lponly_(13, dsi, 2, DPD)			\
+	_lponly_(14, dsib, 7, DPD2)			\
+	_lponly_(15, dsic, 8, DPD2)			\
+	_lponly_(16, dsid, 9, DPD2)			\
+	_lponly_(17, emmc, 3, DPD2)			\
+	_lponly_(18, emmc2, 5, DPD2)			\
+	_lp_n_pv_(19, gpio, 27, 21, 21, DPD)		\
+	_lponly_(20, hdmi, 28, DPD)			\
+	_lponly_(21, hsic, 19, DPD)			\
+	_lponly_(22, lvds, 25, DPD2)			\
+	_lponly_(23, mipi-bias, 3, DPD)			\
+	_lponly_(24, pex-bias, 4, DPD)			\
+	_lponly_(25, pex-clk1, 5, DPD)			\
+	_lponly_(26, pex-clk2, 6, DPD)			\
+	_pvonly_(27, pex-ctrl, 11, 11, DPD2)		\
+	_lp_n_pv_(28, sdmmc1, 1, 12, 12, DPD2)		\
+	_lp_n_pv_(29, sdmmc3, 2, 13, 13, DPD2)		\
+	_lp_n_pv_(30, spi, 14, 22, 22, DPD2)		\
+	_lp_n_pv_(31, spi-hv, 15, 23, 23, DPD2)		\
+	_lp_n_pv_(32, uart, 14, 2, 2, DPD)		\
+	_lponly_(33, usb0, 9, DPD)			\
+	_lponly_(34, usb1, 10, DPD)			\
+	_lponly_(35, usb2, 11, DPD)			\
+	_lponly_(36, usb3, 18, DPD)			\
+	_lponly_(37, usb-bias, 12, DPD)			\
+	_pvonly_(38, sys, 12, UINT_MAX, DPD)
+
 static const struct tegra_io_pad_soc tegra210_io_pads[] = {
-	{ .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = 5 },
-	{ .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = 18 },
-	{ .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = 10 },
-	{ .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIC, .dpd = 42, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSID, .dpd = 43, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIF, .dpd = 45, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = 19 },
-	{ .id = TEGRA_IO_PAD_DEBUG_NONAO, .dpd = 26, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DMIC, .dpd = 50, .voltage = 20 },
-	{ .id = TEGRA_IO_PAD_DP, .dpd = 51, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_EMMC, .dpd = 35, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_EMMC2, .dpd = 37, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_GPIO, .dpd = 27, .voltage = 21 },
-	{ .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = UINT_MAX, .voltage = 11 },
-	{ .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = 12 },
-	{ .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = 13 },
-	{ .id = TEGRA_IO_PAD_SPI, .dpd = 46, .voltage = 22 },
-	{ .id = TEGRA_IO_PAD_SPI_HV, .dpd = 47, .voltage = 23 },
-	{ .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = 2 },
-	{ .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB3, .dpd = 18, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
+	TEGRA210_IO_PAD_TABLE(TEGRA210_IO_PAD_LPONLY, TEGRA210_IO_PAD_PVONLY,
+			      TEGRA210_IO_PAD_LP_N_PV)
+};
+
+static const struct pinctrl_pin_desc tegra210_io_pads_pinctrl_desc[] = {
+	TEGRA210_IO_PAD_TABLE(TEGRA210_IO_PAD_DESC_LP, TEGRA210_IO_PAD_DESC_PV,
+			      TEGRA210_IO_PAD_DESC_LP_N_PV)
 };
 
 static const struct tegra_pmc_soc tegra210_pmc_soc = {
@@ -1782,50 +2204,12 @@  static const struct tegra_pmc_soc tegra210_pmc_soc = {
 	.num_io_pads = ARRAY_SIZE(tegra210_io_pads),
 	.io_pads = tegra210_io_pads,
 	.regs = &tegra20_pmc_regs,
+	.num_descs = ARRAY_SIZE(tegra210_io_pads_pinctrl_desc),
+	.descs = tegra210_io_pads_pinctrl_desc,
 	.init = tegra20_pmc_init,
 	.setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
 };
 
-static const struct tegra_io_pad_soc tegra186_io_pads[] = {
-	{ .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SDMMC2_HV, .dpd = 34, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CAM, .dpd = 38, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSIB, .dpd = 40, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSIC, .dpd = 41, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DSID, .dpd = 42, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_DMIC_HV, .dpd = 52, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX },
-	{ .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX },
-};
-
 static const struct tegra_pmc_regs tegra186_pmc_regs = {
 	.scratch0 = 0x2000,
 	.dpd_req = 0x74,
@@ -1869,6 +2253,111 @@  static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc,
 	iounmap(wake);
 }
 
+#define TEGRA186_IO_PAD_CONFIG(_pin, _npins, _name, _dpd_reg, _dpd_bit,     \
+			       _padv_reg, _padv_bit, _v0, _v1, _iopwr_bit,  \
+			       _bds)  \
+	{							\
+		.name =  #_name,				\
+		.pins = {(_pin)},				\
+		.npins = _npins,				\
+		.dpd_req_reg = TEGRA_PMC_IO_##_dpd_reg##_REQ,	\
+		.dpd_status_reg = TEGRA_PMC_IO_##_dpd_reg##_STATUS,	\
+		.dpd_timer_reg = TEGRA_PMC_SEL_DPD_TIM,		\
+		.dpd_sample_reg = TEGRA_PMC_IO_DPD_SAMPLE,	\
+		.dpd = _dpd_bit,				\
+		.pwr_det_val_reg = TEGRA_PMC_##_padv_reg##_PWR, \
+		.pwr_det_enable_reg = UINT_MAX,		\
+		.pad_uv_0 = TEGRA_IO_PAD_VOLTAGE_##_v0##000UV,	\
+		.pad_uv_1 = TEGRA_IO_PAD_VOLTAGE_##_v1##000UV,	\
+		.voltage = _padv_bit,				\
+		.io_power = _iopwr_bit,				\
+		.bdsdmem_cfc = _bds,				\
+	},
+
+#define TEGRA186_IO_PAD_LPONLY(_pin, _name, _dpd_reg, _dpd_bit, _iopwr_bit, \
+			       _bds)					    \
+	TEGRA186_IO_PAD_CONFIG(_pin, 1, _name, _dpd_reg, _dpd_bit,	    \
+			       E_33V, UINT_MAX, 1200, 1200, _iopwr_bit, _bds)
+
+#define TEGRA186_IO_PAD_LP_N_PV(_pin, _name, _dpd_reg, _dpd_bit, _padv_reg, \
+				_padv_bit, _v0, _v1, _iopwr_bit, _bds)	    \
+	TEGRA186_IO_PAD_CONFIG(_pin, 1, _name, _dpd_reg, _dpd_bit,	    \
+			       _padv_reg, _padv_bit, _v0, _v1, _iopwr_bit,  \
+			       _bds)
+
+#define TEGRA186_IO_PAD_PVONLY(_pin, _name, _padv_reg, _padv_bit, _v0, _v1, \
+			       _iopwr_bit, _bds)			    \
+	TEGRA186_IO_PAD_CONFIG(_pin, 1, _name, DPD, UINT_MAX, _padv_reg,    \
+			       _padv_bit, _v0, _v1, _iopwr_bit, _bds)
+
+#define TEGRA186_IO_PAD_DESC_LP(_pin, _name, _dpd_reg, _dpd_bit, _iopwr_bit, \
+				_bds)					     \
+	{								\
+		.number = _pin,						\
+		.name = #_name,						\
+	},
+
+#define TEGRA186_IO_PAD_DESC_LP_N_PV(_pin, _name, _dpd_reg, _dpd_bit,	\
+				     _padv_reg, _padv_bit, _v0, _v1,	\
+				     _iopwr_bit, _bds)			\
+	TEGRA186_IO_PAD_DESC_LP(_pin, _name, _dpd_reg, _dpd_bit,	\
+				_iopwr_bit, _bds)
+
+#define TEGRA186_IO_PAD_DESC_PV(_pin, _name, _padv_reg, _padv_bit, _v0, _v1, \
+			       _iopwr_bit, _bds)			    \
+	TEGRA186_IO_PAD_DESC_LP(_pin, _name, UINT_MAX, UINT_MAX,	    \
+				UINT_MAX, UINT_MAX)
+
+#define TEGRA186_IO_PAD_TABLE(_lponly_, _pvonly_, _lp_n_pv_)	\
+	_lponly_(0, csia, DPD, 0, UINT_MAX, false)			\
+	_lponly_(1, csib, DPD, 1, UINT_MAX, false)			\
+	_lponly_(2, dsi, DPD, 2, UINT_MAX, false)			\
+	_lponly_(3, mipi-bias, DPD, 3, 9, false)			\
+	_lponly_(4, pex-clk_bias, DPD, 4, UINT_MAX, false)		\
+	_lponly_(5, pex-clk3, DPD, 5, UINT_MAX, false)			\
+	_lponly_(6, pex-clk2, DPD, 6, UINT_MAX, false)			\
+	_lponly_(7, pex-clk1, DPD, 7, UINT_MAX, false)			\
+	_lponly_(8, usb0, DPD, 9, UINT_MAX, false)			\
+	_lponly_(9, usb1, DPD, 10, UINT_MAX, false)			\
+	_lponly_(10, usb2, DPD, 11, UINT_MAX, false)			\
+	_lponly_(11, usb-bias, DPD, 12, UINT_MAX, false)		\
+	_lponly_(12, uart, DPD, 14, 2, false)				\
+	_lponly_(13, audio, DPD, 17, 5, false)				\
+	_lponly_(14, hsic, DPD, 19, UINT_MAX, false)			\
+	_lp_n_pv_(15, dbg, DPD, 25, E_18V, 4, 1200, 1800, 19, false)	\
+	_lponly_(16, hdmi-dp0, DPD, 28, UINT_MAX, false)		\
+	_lponly_(17, hdmi-dp1, DPD, 29, UINT_MAX, false)		\
+	_lponly_(18, pex-ctrl, DPD2, 0, 11, false)			\
+	_lp_n_pv_(19, sdmmc2-hv, DPD2, 2, E_33V, 5, 1800, 3300, 30, true) \
+	_lponly_(20, sdmmc4, DPD2, 4, 14, false)			\
+	_lponly_(21, cam, DPD2, 6, 10, false)				\
+	_lponly_(22, dsib, DPD2, 8, UINT_MAX, false)			\
+	_lponly_(23, dsic, DPD2, 9, UINT_MAX, false)			\
+	_lponly_(24, dsid, DPD2, 10, UINT_MAX, false)			\
+	_lponly_(25, csic, DPD2, 11, UINT_MAX, false)			\
+	_lponly_(26, csid, DPD2, 12, UINT_MAX, false)			\
+	_lponly_(27, csie, DPD2, 13, UINT_MAX, false)			\
+	_lponly_(28, csif, DPD2, 14, UINT_MAX, false)			\
+	_lp_n_pv_(29, spi, DPD2, 15, E_18V, 5, 1200, 1800, 22, false)	\
+	_lp_n_pv_(30, ufs, DPD2, 17, E_18V, 0, 1200, 1800, 6, false)	\
+	_lp_n_pv_(31, dmic-hv, DPD2, 20, E_33V, 2, 1800, 3300, 28, true) \
+	_lponly_(32, edp, DPD2, 21, 4, false)				\
+	_lp_n_pv_(33, sdmmc1-hv, DPD2, 23, E_33V, 4, 1800, 3300, 15, true) \
+	_lp_n_pv_(34, sdmmc3-hv, DPD2, 24, E_33V, 6, 1800, 3300, 31, true) \
+	_lponly_(35, conn, DPD2, 28, 3, false)				\
+	_lp_n_pv_(36, audio-hv, DPD2, 29, E_33V, 1, 1800, 3300, 18, true) \
+	_pvonly_(37, ao-hv, E_33V, 0, 1800, 3300, 27, true)
+
+static const struct tegra_io_pad_soc tegra186_io_pads[] = {
+	TEGRA186_IO_PAD_TABLE(TEGRA186_IO_PAD_LPONLY, TEGRA186_IO_PAD_PVONLY,
+			      TEGRA186_IO_PAD_LP_N_PV)
+};
+
+static const struct pinctrl_pin_desc tegra186_io_pads_pinctrl_desc[] = {
+	TEGRA186_IO_PAD_TABLE(TEGRA186_IO_PAD_DESC_LP, TEGRA186_IO_PAD_DESC_PV,
+			      TEGRA186_IO_PAD_DESC_LP_N_PV)
+};
+
 static const struct tegra_pmc_soc tegra186_pmc_soc = {
 	.num_powergates = 0,
 	.powergates = NULL,
@@ -1878,6 +2367,8 @@  static const struct tegra_pmc_soc tegra186_pmc_soc = {
 	.has_gpu_clamps = false,
 	.num_io_pads = ARRAY_SIZE(tegra186_io_pads),
 	.io_pads = tegra186_io_pads,
+	.num_descs = ARRAY_SIZE(tegra186_io_pads_pinctrl_desc),
+	.descs = tegra186_io_pads_pinctrl_desc,
 	.regs = &tegra186_pmc_regs,
 	.init = NULL,
 	.setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h
index c32bf91..c3acc2e 100644
--- a/include/soc/tegra/pmc.h
+++ b/include/soc/tegra/pmc.h
@@ -1,6 +1,6 @@ 
 /*
  * Copyright (c) 2010 Google, Inc
- * Copyright (c) 2014 NVIDIA Corporation
+ * Copyright (c) 2014-2018 NVIDIA Corporation
  *
  * Author:
  *	Colin Cross <ccross@google.com>
@@ -160,11 +160,10 @@  int tegra_powergate_remove_clamping(unsigned int id);
 int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
 				      struct reset_control *rst);
 
-int tegra_io_pad_power_enable(enum tegra_io_pad id);
-int tegra_io_pad_power_disable(enum tegra_io_pad id);
-int tegra_io_pad_set_voltage(enum tegra_io_pad id,
-			     enum tegra_io_pad_voltage voltage);
-int tegra_io_pad_get_voltage(enum tegra_io_pad id);
+int tegra_pmc_io_pad_low_power_enable(const char *pad_name);
+int tegra_pmc_io_pad_low_power_disable(const char *pad_name);
+int tegra_pmc_io_pad_set_voltage(const char *pad_name, unsigned int pad_uv);
+int tegra_pmc_io_pad_get_voltage(const char *pad_name);
 
 /* deprecated, use tegra_io_pad_power_{enable,disable}() instead */
 int tegra_io_rail_power_on(unsigned int id);
@@ -202,23 +201,23 @@  static inline int tegra_powergate_sequence_power_up(unsigned int id,
 	return -ENOSYS;
 }
 
-static inline int tegra_io_pad_power_enable(enum tegra_io_pad id)
+static inline int tegra_pmc_io_pad_low_power_enable(const char *pad_name)
 {
 	return -ENOSYS;
 }
 
-static inline int tegra_io_pad_power_disable(enum tegra_io_pad id)
+static inline int tegra_pmc_io_pad_low_power_disable(const char *pad_name)
 {
 	return -ENOSYS;
 }
 
-static inline int tegra_io_pad_set_voltage(enum tegra_io_pad id,
-					   enum tegra_io_pad_voltage voltage)
+static inline int tegra_pmc_io_pad_set_voltage(const char *pad_name,
+					       unsigned int pad_uv)
 {
 	return -ENOSYS;
 }
 
-static inline int tegra_io_pad_get_voltage(enum tegra_io_pad id)
+static inline int tegra_pmc_io_pad_get_voltage(const char *pad_name)
 {
 	return -ENOSYS;
 }