/*
 * Copyright (c) 2011 The Chromium OS Authors.
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

/* Tegra20 pin multiplexing functions */

#include <common.h>
#include <asm/io.h>
#include <asm/arch/tegra.h>
#include <asm/arch/pinmux.h>


/*
 * This defines the order of the pin mux control bits in the registers. For
 * some reason there is no correspendence between the tristate, pin mux and
 * pullup/pulldown registers.
 */
enum pmux_ctlid {
	/* 0: APB_MISC_PP_PIN_MUX_CTL_A_0 */
	MUXCTL_UAA,
	MUXCTL_UAB,
	MUXCTL_UAC,
	MUXCTL_UAD,
	MUXCTL_UDA,
	MUXCTL_RESERVED5,
	MUXCTL_ATE,
	MUXCTL_RM,

	MUXCTL_ATB,
	MUXCTL_RESERVED9,
	MUXCTL_ATD,
	MUXCTL_ATC,
	MUXCTL_ATA,
	MUXCTL_KBCF,
	MUXCTL_KBCE,
	MUXCTL_SDMMC1,

	/* 16: APB_MISC_PP_PIN_MUX_CTL_B_0 */
	MUXCTL_GMA,
	MUXCTL_GMC,
	MUXCTL_HDINT,
	MUXCTL_SLXA,
	MUXCTL_OWC,
	MUXCTL_SLXC,
	MUXCTL_SLXD,
	MUXCTL_SLXK,

	MUXCTL_UCA,
	MUXCTL_UCB,
	MUXCTL_DTA,
	MUXCTL_DTB,
	MUXCTL_RESERVED28,
	MUXCTL_DTC,
	MUXCTL_DTD,
	MUXCTL_DTE,

	/* 32: APB_MISC_PP_PIN_MUX_CTL_C_0 */
	MUXCTL_DDC,
	MUXCTL_CDEV1,
	MUXCTL_CDEV2,
	MUXCTL_CSUS,
	MUXCTL_I2CP,
	MUXCTL_KBCA,
	MUXCTL_KBCB,
	MUXCTL_KBCC,

	MUXCTL_IRTX,
	MUXCTL_IRRX,
	MUXCTL_DAP1,
	MUXCTL_DAP2,
	MUXCTL_DAP3,
	MUXCTL_DAP4,
	MUXCTL_GMB,
	MUXCTL_GMD,

	/* 48: APB_MISC_PP_PIN_MUX_CTL_D_0 */
	MUXCTL_GME,
	MUXCTL_GPV,
	MUXCTL_GPU,
	MUXCTL_SPDO,
	MUXCTL_SPDI,
	MUXCTL_SDB,
	MUXCTL_SDC,
	MUXCTL_SDD,

	MUXCTL_SPIH,
	MUXCTL_SPIG,
	MUXCTL_SPIF,
	MUXCTL_SPIE,
	MUXCTL_SPID,
	MUXCTL_SPIC,
	MUXCTL_SPIB,
	MUXCTL_SPIA,

	/* 64: APB_MISC_PP_PIN_MUX_CTL_E_0 */
	MUXCTL_LPW0,
	MUXCTL_LPW1,
	MUXCTL_LPW2,
	MUXCTL_LSDI,
	MUXCTL_LSDA,
	MUXCTL_LSPI,
	MUXCTL_LCSN,
	MUXCTL_LDC,

	MUXCTL_LSCK,
	MUXCTL_LSC0,
	MUXCTL_LSC1,
	MUXCTL_LHS,
	MUXCTL_LVS,
	MUXCTL_LM0,
	MUXCTL_LM1,
	MUXCTL_LVP0,

	/* 80: APB_MISC_PP_PIN_MUX_CTL_F_0 */
	MUXCTL_LD0,
	MUXCTL_LD1,
	MUXCTL_LD2,
	MUXCTL_LD3,
	MUXCTL_LD4,
	MUXCTL_LD5,
	MUXCTL_LD6,
	MUXCTL_LD7,

	MUXCTL_LD8,
	MUXCTL_LD9,
	MUXCTL_LD10,
	MUXCTL_LD11,
	MUXCTL_LD12,
	MUXCTL_LD13,
	MUXCTL_LD14,
	MUXCTL_LD15,

	/* 96: APB_MISC_PP_PIN_MUX_CTL_G_0 */
	MUXCTL_LD16,
	MUXCTL_LD17,
	MUXCTL_LHP1,
	MUXCTL_LHP2,
	MUXCTL_LVP1,
	MUXCTL_LHP0,
	MUXCTL_RESERVED102,
	MUXCTL_LPP,

	MUXCTL_LDI,
	MUXCTL_PMC,
	MUXCTL_CRTP,
	MUXCTL_PTA,
	MUXCTL_RESERVED108,
	MUXCTL_KBCD,
	MUXCTL_GPU7,
	MUXCTL_DTF,

	MUXCTL_NONE = -1,
};

/*
 * And this defines the order of the pullup/pulldown controls which are again
 * in a different order
 */
enum pmux_pullid {
	/* 0: APB_MISC_PP_PULLUPDOWN_REG_A_0 */
	PUCTL_ATA,
	PUCTL_ATB,
	PUCTL_ATC,
	PUCTL_ATD,
	PUCTL_ATE,
	PUCTL_DAP1,
	PUCTL_DAP2,
	PUCTL_DAP3,

	PUCTL_DAP4,
	PUCTL_DTA,
	PUCTL_DTB,
	PUCTL_DTC,
	PUCTL_DTD,
	PUCTL_DTE,
	PUCTL_DTF,
	PUCTL_GPV,

	/* 16: APB_MISC_PP_PULLUPDOWN_REG_B_0 */
	PUCTL_RM,
	PUCTL_I2CP,
	PUCTL_PTA,
	PUCTL_GPU7,
	PUCTL_KBCA,
	PUCTL_KBCB,
	PUCTL_KBCC,
	PUCTL_KBCD,

	PUCTL_SPDI,
	PUCTL_SPDO,
	PUCTL_GPSLXAU,
	PUCTL_CRTP,
	PUCTL_SLXC,
	PUCTL_SLXD,
	PUCTL_SLXK,

	/* 32: APB_MISC_PP_PULLUPDOWN_REG_C_0 */
	PUCTL_CDEV1,
	PUCTL_CDEV2,
	PUCTL_SPIA,
	PUCTL_SPIB,
	PUCTL_SPIC,
	PUCTL_SPID,
	PUCTL_SPIE,
	PUCTL_SPIF,

	PUCTL_SPIG,
	PUCTL_SPIH,
	PUCTL_IRTX,
	PUCTL_IRRX,
	PUCTL_GME,
	PUCTL_RESERVED45,
	PUCTL_XM2D,
	PUCTL_XM2C,

	/* 48: APB_MISC_PP_PULLUPDOWN_REG_D_0 */
	PUCTL_UAA,
	PUCTL_UAB,
	PUCTL_UAC,
	PUCTL_UAD,
	PUCTL_UCA,
	PUCTL_UCB,
	PUCTL_LD17,
	PUCTL_LD19_18,

	PUCTL_LD21_20,
	PUCTL_LD23_22,
	PUCTL_LS,
	PUCTL_LC,
	PUCTL_CSUS,
	PUCTL_DDRC,
	PUCTL_SDC,
	PUCTL_SDD,

	/* 64: APB_MISC_PP_PULLUPDOWN_REG_E_0 */
	PUCTL_KBCF,
	PUCTL_KBCE,
	PUCTL_PMCA,
	PUCTL_PMCB,
	PUCTL_PMCC,
	PUCTL_PMCD,
	PUCTL_PMCE,
	PUCTL_CK32,

	PUCTL_UDA,
	PUCTL_SDMMC1,
	PUCTL_GMA,
	PUCTL_GMB,
	PUCTL_GMC,
	PUCTL_GMD,
	PUCTL_DDC,
	PUCTL_OWC,

	PUCTL_NONE = -1
};

struct tegra_pingroup_desc {
	const char *name;
	enum pmux_func funcs[4];
	enum pmux_func func_safe;
	enum pmux_vddio vddio;
	enum pmux_ctlid ctl_id;
	enum pmux_pullid pull_id;
};


/* Converts a pmux_pingrp number to a tristate register: 0=A, 1=B, 2=C, 3=D */
#define TRISTATE_REG(pmux_pingrp) ((pmux_pingrp) >> 5)

/* Mask value for a tristate (within TRISTATE_REG(id)) */
#define TRISTATE_MASK(pmux_pingrp) (1 << ((pmux_pingrp) & 0x1f))

/* Converts a PUCTL id to a pull register: 0=A, 1=B...4=E */
#define PULL_REG(pmux_pullid) ((pmux_pullid) >> 4)

/* Converts a PUCTL id to a shift position */
#define PULL_SHIFT(pmux_pullid) ((pmux_pullid << 1) & 0x1f)

/* Converts a MUXCTL id to a ctl register: 0=A, 1=B...6=G */
#define MUXCTL_REG(pmux_ctlid) ((pmux_ctlid) >> 4)

/* Converts a MUXCTL id to a shift position */
#define MUXCTL_SHIFT(pmux_ctlid) ((pmux_ctlid << 1) & 0x1f)

/* Convenient macro for defining pin group properties */
#define PINALL(pg_name, vdd, f0, f1, f2, f3, f_safe, mux, pupd)		\
	{						\
		.vddio = PMUX_VDDIO_ ## vdd,		\
		.funcs = {				\
			PMUX_FUNC_ ## f0,			\
			PMUX_FUNC_ ## f1,			\
			PMUX_FUNC_ ## f2,			\
			PMUX_FUNC_ ## f3,			\
		},					\
		.func_safe = PMUX_FUNC_ ## f_safe,		\
		.ctl_id = mux,				\
		.pull_id = pupd				\
	}

/* A normal pin group where the mux name and pull-up name match */
#define PIN(pg_name, vdd, f0, f1, f2, f3, f_safe)		\
		PINALL(pg_name, vdd, f0, f1, f2, f3, f_safe,	\
			MUXCTL_ ## pg_name, PUCTL_ ## pg_name)

/* A pin group where the pull-up name doesn't have a 1-1 mapping */
#define PINP(pg_name, vdd, f0, f1, f2, f3, f_safe, pupd)		\
		PINALL(pg_name, vdd, f0, f1, f2, f3, f_safe,	\
			MUXCTL_ ## pg_name, PUCTL_ ## pupd)

/* A pin group number which is not used */
#define PIN_RESERVED \
	PIN(NONE, NONE, NONE, NONE, NONE, NONE, NONE)

const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = {
	PIN(ATA,  NAND,  IDE,    NAND,   GMI,       RSVD,        IDE),
	PIN(ATB,  NAND,  IDE,    NAND,   GMI,       SDIO4,       IDE),
	PIN(ATC,  NAND,  IDE,    NAND,   GMI,       SDIO4,       IDE),
	PIN(ATD,  NAND,  IDE,    NAND,   GMI,       SDIO4,       IDE),
	PIN(CDEV1, AUDIO, OSC,   PLLA_OUT, PLLM_OUT1, AUDIO_SYNC, OSC),
	PIN(CDEV2, AUDIO, OSC,   AHB_CLK, APB_CLK, PLLP_OUT4,    OSC),
	PIN(CSUS, VI, PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK,
		PLLC_OUT1),
	PIN(DAP1, AUDIO, DAP1,   RSVD,   GMI,       SDIO2,       DAP1),

	PIN(DAP2, AUDIO, DAP2,   TWC,    RSVD,      GMI,         DAP2),
	PIN(DAP3, BB,    DAP3,   RSVD,   RSVD,      RSVD,        DAP3),
	PIN(DAP4, UART,  DAP4,   RSVD,   GMI,       RSVD,        DAP4),
	PIN(DTA,  VI,    RSVD,   SDIO2,  VI,        RSVD,        RSVD4),
	PIN(DTB,  VI,    RSVD,   RSVD,   VI,        SPI1,        RSVD1),
	PIN(DTC,  VI,    RSVD,   RSVD,   VI,        RSVD,        RSVD1),
	PIN(DTD,  VI,    RSVD,   SDIO2,  VI,        RSVD,        RSVD1),
	PIN(DTE,  VI,    RSVD,   RSVD,   VI,        SPI1,        RSVD1),

	PINP(GPU, UART,  PWM,    UARTA,  GMI,       RSVD,        RSVD4,
		GPSLXAU),
	PIN(GPV,  SD,    PCIE,   RSVD,   RSVD,      RSVD,        PCIE),
	PIN(I2CP, SYS,   I2C,    RSVD,   RSVD,      RSVD,        RSVD4),
	PIN(IRTX, UART,  UARTA,  UARTB,  GMI,       SPI4,        UARTB),
	PIN(IRRX, UART,  UARTA,  UARTB,  GMI,       SPI4,        UARTB),
	PIN(KBCB, SYS,   KBC,    NAND,   SDIO2,     MIO,         KBC),
	PIN(KBCA, SYS,   KBC,    NAND,   SDIO2,     EMC_TEST0_DLL, KBC),
	PINP(PMC, SYS,   PWR_ON, PWR_INTR, RSVD,    RSVD,        PWR_ON, NONE),

	PIN(PTA,  NAND,  I2C2,   HDMI,   GMI,       RSVD,        RSVD4),
	PIN(RM,   UART,  I2C,    RSVD,   RSVD,      RSVD,        RSVD4),
	PIN(KBCE, SYS,   KBC,    NAND,   OWR,       RSVD,        KBC),
	PIN(KBCF, SYS,   KBC,    NAND,   TRACE,     MIO,         KBC),
	PIN(GMA,  NAND,  UARTE,  SPI3,   GMI,       SDIO4,       SPI3),
	PIN(GMC,  NAND,  UARTD,  SPI4,   GMI,       SFLASH,      SPI4),
	PIN(SDMMC1, BB,  SDIO1,  RSVD,   UARTE,     UARTA,       RSVD2),
	PIN(OWC,  SYS,   OWR,    RSVD,   RSVD,      RSVD,        OWR),

	PIN(GME,  NAND,  RSVD,   DAP5,   GMI,       SDIO4,       GMI),
	PIN(SDC,  SD,    PWM,    TWC,    SDIO3,     SPI3,        TWC),
	PIN(SDD,  SD,    UARTA,  PWM,    SDIO3,     SPI3,        PWM),
	PIN_RESERVED,
	PINP(SLXA, SD,   PCIE,   SPI4,   SDIO3,     SPI2,        PCIE, CRTP),
	PIN(SLXC, SD,    SPDIF,  SPI4,   SDIO3,     SPI2,        SPI4),
	PIN(SLXD, SD,    SPDIF,  SPI4,   SDIO3,     SPI2,        SPI4),
	PIN(SLXK, SD,    PCIE,   SPI4,   SDIO3,     SPI2,        PCIE),

	PIN(SPDI, AUDIO, SPDIF,  RSVD,   I2C,       SDIO2,       RSVD2),
	PIN(SPDO, AUDIO, SPDIF,  RSVD,   I2C,       SDIO2,       RSVD2),
	PIN(SPIA, AUDIO, SPI1,   SPI2,   SPI3,      GMI,         GMI),
	PIN(SPIB, AUDIO, SPI1,   SPI2,   SPI3,      GMI,         GMI),
	PIN(SPIC, AUDIO, SPI1,   SPI2,   SPI3,      GMI,         GMI),
	PIN(SPID, AUDIO, SPI2,   SPI1,   SPI2_ALT,  GMI,         GMI),
	PIN(SPIE, AUDIO, SPI2,   SPI1,   SPI2_ALT,  GMI,         GMI),
	PIN(SPIF, AUDIO, SPI3,   SPI1,   SPI2,      RSVD,        RSVD4),

	PIN(SPIG, AUDIO, SPI3,   SPI2,   SPI2_ALT,  I2C,         SPI2_ALT),
	PIN(SPIH, AUDIO, SPI3,   SPI2,   SPI2_ALT,  I2C,         SPI2_ALT),
	PIN(UAA,  BB,    SPI3,   MIPI_HS, UARTA,    ULPI,        MIPI_HS),
	PIN(UAB,  BB,    SPI2,   MIPI_HS, UARTA,    ULPI,        MIPI_HS),
	PIN(UAC,  BB,    OWR,    RSVD,   RSVD,      RSVD,        RSVD4),
	PIN(UAD,  UART,  IRDA,   SPDIF,  UARTA,     SPI4,        SPDIF),
	PIN(UCA,  UART,  UARTC,  RSVD,   GMI,       RSVD,        RSVD4),
	PIN(UCB,  UART,  UARTC,  PWM,    GMI,       RSVD,        RSVD4),

	PIN_RESERVED,
	PIN(ATE,  NAND,  IDE,    NAND,   GMI,       RSVD,        IDE),
	PIN(KBCC, SYS,   KBC,    NAND,   TRACE,     EMC_TEST1_DLL, KBC),
	PIN_RESERVED,
	PIN_RESERVED,
	PIN(GMB,  NAND,  IDE,    NAND,   GMI,       GMI_INT,     GMI),
	PIN(GMD,  NAND,  RSVD,   NAND,   GMI,       SFLASH,      GMI),
	PIN(DDC,  LCD,   I2C2,   RSVD,   RSVD,      RSVD,        RSVD4),

	/* 64 */
	PINP(LD0,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD1,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD2,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD3,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD4,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD5,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD6,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD7,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),

	PINP(LD8,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD9,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD10, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD11, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD12, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD13, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD14, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD15, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),

	PINP(LD16, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LD17),
	PINP(LD17, LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LD17),
	PINP(LHP0, LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LD21_20),
	PINP(LHP1, LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LD19_18),
	PINP(LHP2, LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LD19_18),
	PINP(LVP0, LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LC),
	PINP(LVP1, LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LD21_20),
	PINP(HDINT, LCD, HDMI,   RSVD,   RSVD,      RSVD,     HDMI , LC),

	PINP(LM0,  LCD,  DISPA,  DISPB,  SPI3,      RSVD,     RSVD4, LC),
	PINP(LM1,  LCD,  DISPA,  DISPB,  RSVD,      CRT,      RSVD3, LC),
	PINP(LVS,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LC),
	PINP(LSC0, LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LC),
	PINP(LSC1, LCD,  DISPA,  DISPB,  SPI3,      HDMI,     DISPA, LS),
	PINP(LSCK, LCD,  DISPA,  DISPB,  SPI3,      HDMI,     DISPA, LS),
	PINP(LDC,  LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LS),
	PINP(LCSN, LCD,  DISPA,  DISPB,  SPI3,      RSVD,     RSVD4, LS),

	/* 96 */
	PINP(LSPI, LCD,  DISPA,  DISPB,  XIO,       HDMI,     DISPA, LC),
	PINP(LSDA, LCD,  DISPA,  DISPB,  SPI3,      HDMI,     DISPA, LS),
	PINP(LSDI, LCD,  DISPA,  DISPB,  SPI3,      RSVD,     DISPA, LS),
	PINP(LPW0, LCD,  DISPA,  DISPB,  SPI3,      HDMI,     DISPA, LS),
	PINP(LPW1, LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LS),
	PINP(LPW2, LCD,  DISPA,  DISPB,  SPI3,      HDMI,     DISPA, LS),
	PINP(LDI,  LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LD23_22),
	PINP(LHS,  LCD,  DISPA,  DISPB,  XIO,       RSVD,     RSVD4, LC),

	PINP(LPP,  LCD,  DISPA,  DISPB,  RSVD,      RSVD,     RSVD4, LD23_22),
	PIN_RESERVED,
	PIN(KBCD,  SYS,  KBC,    NAND,   SDIO2,     MIO,      KBC),
	PIN(GPU7,  SYS,  RTCK,   RSVD,   RSVD,      RSVD,     RTCK),
	PIN(DTF,   VI,   I2C3,   RSVD,   VI,        RSVD,     RSVD4),
	PIN(UDA,   BB,   SPI1,   RSVD,   UARTD,     ULPI,     RSVD2),
	PIN(CRTP,  LCD,  CRT,    RSVD,   RSVD,      RSVD,     RSVD),
	PINP(SDB,  SD,   UARTA,  PWM,    SDIO3,     SPI2,     PWM,   NONE),

	/* these pin groups only have pullup and pull down control */
	PINALL(CK32,  SYS,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(DDRC,  DDR,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(PMCA,  SYS,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(PMCB,  SYS,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(PMCC,  SYS,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(PMCD,  SYS,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(PMCE,  SYS,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(XM2C,  DDR,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
	PINALL(XM2D,  DDR,   RSVD, RSVD, RSVD, RSVD,  RSVD, MUXCTL_NONE,
		PUCTL_NONE),
};

void pinmux_set_tristate(enum pmux_pingrp pin, int enable)
{
	struct pmux_tri_ctlr *pmt =
			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
	u32 *tri = &pmt->pmt_tri[TRISTATE_REG(pin)];
	u32 reg;

	reg = readl(tri);
	if (enable)
		reg |= TRISTATE_MASK(pin);
	else
		reg &= ~TRISTATE_MASK(pin);
	writel(reg, tri);
}

void pinmux_tristate_enable(enum pmux_pingrp pin)
{
	pinmux_set_tristate(pin, 1);
}

void pinmux_tristate_disable(enum pmux_pingrp pin)
{
	pinmux_set_tristate(pin, 0);
}

void pinmux_set_pullupdown(enum pmux_pingrp pin, enum pmux_pull pupd)
{
	struct pmux_tri_ctlr *pmt =
			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
	enum pmux_pullid pull_id = tegra_soc_pingroups[pin].pull_id;
	u32 *pull = &pmt->pmt_pull[PULL_REG(pull_id)];
	u32 mask_bit;
	u32 reg;
	mask_bit = PULL_SHIFT(pull_id);

	reg = readl(pull);
	reg &= ~(0x3 << mask_bit);
	reg |= pupd << mask_bit;
	writel(reg, pull);
}

void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func)
{
	struct pmux_tri_ctlr *pmt =
			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
	enum pmux_ctlid mux_id = tegra_soc_pingroups[pin].ctl_id;
	u32 *muxctl = &pmt->pmt_ctl[MUXCTL_REG(mux_id)];
	u32 mask_bit;
	int i, mux = -1;
	u32 reg;

	assert(pmux_func_isvalid(func));

	/* Handle special values */
	if (func >= PMUX_FUNC_RSVD1) {
		mux = (func - PMUX_FUNC_RSVD1) & 0x3;
	} else {
		/* Search for the appropriate function */
		for (i = 0; i < 4; i++) {
			if (tegra_soc_pingroups[pin].funcs[i] == func) {
				mux = i;
				break;
			}
		}
	}
	assert(mux != -1);

	mask_bit = MUXCTL_SHIFT(mux_id);
	reg = readl(muxctl);
	reg &= ~(0x3 << mask_bit);
	reg |= mux << mask_bit;
	writel(reg, muxctl);
}

void pinmux_config_pingroup(struct pingroup_config *config)
{
	enum pmux_pingrp pin = config->pingroup;

	pinmux_set_func(pin, config->func);
	pinmux_set_pullupdown(pin, config->pull);
	pinmux_set_tristate(pin, config->tristate);
}

void pinmux_config_table(struct pingroup_config *config, int len)
{
	int i;

	for (i = 0; i < len; i++)
		pinmux_config_pingroup(&config[i]);
}
