Tegra114: Dalmore: Add pad config tables/code based on pinmux code

Pad config registers exist in APB_MISC_GP space, and control slew
rate, drive strengh, schmidt, high-speed, and low-power modes for
all of the pingroups in Tegra30. This builds off of the pinmux
way of constructing init tables to configure select pads (SDIOCFG,
for instance) during pinmux_init().

Currently, no padcfg entries exist. SDIO3CFG will be added when the
MMC driver is added as per the TRM to work with the SD-card slot on
Dalmore E1611.

Signed-off-by: Tom Warren <twarren@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
diff --git a/arch/arm/cpu/tegra114-common/pinmux.c b/arch/arm/cpu/tegra114-common/pinmux.c
index 16368c5..4983a05 100644
--- a/arch/arm/cpu/tegra114-common/pinmux.c
+++ b/arch/arm/cpu/tegra114-common/pinmux.c
@@ -39,6 +39,19 @@
 #define PMUX_IO_RESET_SHIFT	8
 #define PMUX_RCV_SEL_SHIFT	9
 
+#define PGRP_HSM_SHIFT		2
+#define PGRP_SCHMT_SHIFT	3
+#define PGRP_LPMD_SHIFT		4
+#define PGRP_LPMD_MASK		(3 << PGRP_LPMD_SHIFT)
+#define PGRP_DRVDN_SHIFT	12
+#define PGRP_DRVDN_MASK		(0x7F << PGRP_DRVDN_SHIFT)
+#define PGRP_DRVUP_SHIFT	20
+#define PGRP_DRVUP_MASK		(0x7F << PGRP_DRVUP_SHIFT)
+#define PGRP_SLWR_SHIFT		28
+#define PGRP_SLWR_MASK		(3 << PGRP_SLWR_SHIFT)
+#define PGRP_SLWF_SHIFT		30
+#define PGRP_SLWF_MASK		(3 << PGRP_SLWF_SHIFT)
+
 /* Convenient macro for defining pin group properties */
 #define PIN(pg_name, vdd, f0, f1, f2, f3, iod)	\
 	{						\
@@ -544,3 +557,184 @@
 	for (i = 0; i < len; i++)
 		pinmux_config_pingroup(&config[i]);
 }
+
+static int padgrp_set_drvup_slwf(enum pdrive_pingrp pad, int slwf)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pad_slwf = &pmt->pmt_drive[pad];
+	u32 reg;
+
+	/* Error check on pad and slwf */
+	assert(pmux_padgrp_isvalid(pad));
+	assert(pmux_pad_slw_isvalid(slwf));
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (slwf == PGRP_SLWF_NONE)
+		return 0;
+
+	reg = readl(pad_slwf);
+	reg &= ~PGRP_SLWF_MASK;
+	reg |= (slwf << PGRP_SLWF_SHIFT);
+	writel(reg, pad_slwf);
+
+	return 0;
+}
+
+static int padgrp_set_drvdn_slwr(enum pdrive_pingrp pad, int slwr)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pad_slwr = &pmt->pmt_drive[pad];
+	u32 reg;
+
+	/* Error check on pad and slwr */
+	assert(pmux_padgrp_isvalid(pad));
+	assert(pmux_pad_slw_isvalid(slwr));
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (slwr == PGRP_SLWR_NONE)
+		return 0;
+
+	reg = readl(pad_slwr);
+	reg &= ~PGRP_SLWR_MASK;
+	reg |= (slwr << PGRP_SLWR_SHIFT);
+	writel(reg, pad_slwr);
+
+	return 0;
+}
+
+static int padgrp_set_drvup(enum pdrive_pingrp pad, int drvup)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pad_drvup = &pmt->pmt_drive[pad];
+	u32 reg;
+
+	/* Error check on pad and drvup */
+	assert(pmux_padgrp_isvalid(pad));
+	assert(pmux_pad_drv_isvalid(drvup));
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (drvup == PGRP_DRVUP_NONE)
+		return 0;
+
+	reg = readl(pad_drvup);
+	reg &= ~PGRP_DRVUP_MASK;
+	reg |= (drvup << PGRP_DRVUP_SHIFT);
+	writel(reg, pad_drvup);
+
+	return 0;
+}
+
+static int padgrp_set_drvdn(enum pdrive_pingrp pad, int drvdn)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pad_drvdn = &pmt->pmt_drive[pad];
+	u32 reg;
+
+	/* Error check on pad and drvdn */
+	assert(pmux_padgrp_isvalid(pad));
+	assert(pmux_pad_drv_isvalid(drvdn));
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (drvdn == PGRP_DRVDN_NONE)
+		return 0;
+
+	reg = readl(pad_drvdn);
+	reg &= ~PGRP_DRVDN_MASK;
+	reg |= (drvdn << PGRP_DRVDN_SHIFT);
+	writel(reg, pad_drvdn);
+
+	return 0;
+}
+
+static int padgrp_set_lpmd(enum pdrive_pingrp pad, enum pgrp_lpmd lpmd)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pad_lpmd = &pmt->pmt_drive[pad];
+	u32 reg;
+
+	/* Error check pad and lpmd value */
+	assert(pmux_padgrp_isvalid(pad));
+	assert(pmux_pad_lpmd_isvalid(lpmd));
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (lpmd == PGRP_LPMD_NONE)
+		return 0;
+
+	reg = readl(pad_lpmd);
+	reg &= ~PGRP_LPMD_MASK;
+	reg |= (lpmd << PGRP_LPMD_SHIFT);
+	writel(reg, pad_lpmd);
+
+	return 0;
+}
+
+static int padgrp_set_schmt(enum pdrive_pingrp pad, enum pgrp_schmt schmt)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pad_schmt = &pmt->pmt_drive[pad];
+	u32 reg;
+
+	/* Error check pad */
+	assert(pmux_padgrp_isvalid(pad));
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (schmt == PGRP_SCHMT_NONE)
+		return 0;
+
+	reg = readl(pad_schmt);
+	reg &= ~(1 << PGRP_SCHMT_SHIFT);
+	if (schmt == PGRP_SCHMT_ENABLE)
+		reg |= (0x1 << PGRP_SCHMT_SHIFT);
+	writel(reg, pad_schmt);
+
+	return 0;
+}
+static int padgrp_set_hsm(enum pdrive_pingrp pad, enum pgrp_hsm hsm)
+{
+	struct pmux_tri_ctlr *pmt =
+			(struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE;
+	u32 *pad_hsm = &pmt->pmt_drive[pad];
+	u32 reg;
+
+	/* Error check pad */
+	assert(pmux_padgrp_isvalid(pad));
+
+	/* NONE means unspecified/do not change/use POR value */
+	if (hsm == PGRP_HSM_NONE)
+		return 0;
+
+	reg = readl(pad_hsm);
+	reg &= ~(1 << PGRP_HSM_SHIFT);
+	if (hsm == PGRP_HSM_ENABLE)
+		reg |= (0x1 << PGRP_HSM_SHIFT);
+	writel(reg, pad_hsm);
+
+	return 0;
+}
+
+void padctrl_config_pingroup(struct padctrl_config *config)
+{
+	enum pdrive_pingrp pad = config->padgrp;
+
+	padgrp_set_drvup_slwf(pad, config->slwf);
+	padgrp_set_drvdn_slwr(pad, config->slwr);
+	padgrp_set_drvup(pad, config->drvup);
+	padgrp_set_drvdn(pad, config->drvdn);
+	padgrp_set_lpmd(pad, config->lpmd);
+	padgrp_set_schmt(pad, config->schmt);
+	padgrp_set_hsm(pad, config->hsm);
+}
+
+void padgrp_config_table(struct padctrl_config *config, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		padctrl_config_pingroup(&config[i]);
+}
diff --git a/arch/arm/include/asm/arch-tegra114/pinmux.h b/arch/arm/include/asm/arch-tegra114/pinmux.h
index 53905cb..9c22c08 100644
--- a/arch/arm/include/asm/arch-tegra114/pinmux.h
+++ b/arch/arm/include/asm/arch-tegra114/pinmux.h
@@ -215,34 +215,35 @@
 	PDRIVE_PINGROUP_AT5,
 	PDRIVE_PINGROUP_CDEV1,
 	PDRIVE_PINGROUP_CDEV2,
-	PDRIVE_PINGROUP_CSUS,
-	PDRIVE_PINGROUP_DAP1,
+	PDRIVE_PINGROUP_DAP1 = 10,	/* offset 0x890 */
 	PDRIVE_PINGROUP_DAP2,
 	PDRIVE_PINGROUP_DAP3,
 	PDRIVE_PINGROUP_DAP4,
 	PDRIVE_PINGROUP_DBG,
-	PDRIVE_PINGROUP_SDIO3,
+	PDRIVE_PINGROUP_SDIO3 = 18,	/* offset 0x8B0 */
 	PDRIVE_PINGROUP_SPI,
 	PDRIVE_PINGROUP_UAA,
 	PDRIVE_PINGROUP_UAB,
 	PDRIVE_PINGROUP_UART2,
 	PDRIVE_PINGROUP_UART3,
-	PDRIVE_PINGROUP_SDIO1 = 33,     /* offset 0x8ec */
-	PDRIVE_PINGROUP_CRT = 36,       /* offset 0x8f8 */
-	PDRIVE_PINGROUP_DDC,
+	PDRIVE_PINGROUP_SDIO1 = 33,     /* offset 0x8EC */
+	PDRIVE_PINGROUP_DDC = 37,       /* offset 0x8FC */
 	PDRIVE_PINGROUP_GMA,
-	PDRIVE_PINGROUP_GME,
+	PDRIVE_PINGROUP_GME = 42,	/* offset 0x910 */
 	PDRIVE_PINGROUP_GMF,
 	PDRIVE_PINGROUP_GMG,
 	PDRIVE_PINGROUP_GMH,
 	PDRIVE_PINGROUP_OWR,
 	PDRIVE_PINGROUP_UAD,
-	PDRIVE_PINGROUP_GPV,
 	PDRIVE_PINGROUP_DEV3 = 49,      /* offset 0x92c */
 	PDRIVE_PINGROUP_CEC = 52,       /* offset 0x938 */
-	PDRIVE_PINGROUP_AT6,
+	PDRIVE_PINGROUP_AT6 = 75,	/* offset 0x994 */
 	PDRIVE_PINGROUP_DAP5,
 	PDRIVE_PINGROUP_VBUS,
+	PDRIVE_PINGROUP_AO3,
+	PDRIVE_PINGROUP_HVC,
+	PDRIVE_PINGROUP_SDIO4,
+	PDRIVE_PINGROUP_AO0,
 	PDRIVE_PINGROUP_COUNT,
 };
 
@@ -470,10 +471,73 @@
 	PMUX_VDDIO_NONE
 };
 
-/* T114 pin drive group and pin mux registers */
-#define PDRIVE_PINGROUP_OFFSET  (0x868 >> 2)
-#define PMUX_OFFSET     ((0x3000 >> 2) - PDRIVE_PINGROUP_OFFSET - \
-			PDRIVE_PINGROUP_COUNT)
+#define PGRP_SLWF_NONE	-1
+#define PGRP_SLWF_MAX	3
+#define PGRP_SLWR_NONE	PGRP_SLWF_NONE
+#define PGRP_SLWR_MAX	PGRP_SLWF_MAX
+
+#define PGRP_DRVUP_NONE	-1
+#define PGRP_DRVUP_MAX	127
+#define PGRP_DRVDN_NONE	PGRP_DRVUP_NONE
+#define PGRP_DRVDN_MAX	PGRP_DRVUP_MAX
+
+#define PGRP_SCHMT_NONE	-1
+#define PGRP_HSM_NONE	PGRP_SCHMT_NONE
+
+/* return 1 if a padgrp is in range */
+#define pmux_padgrp_isvalid(pd) (((pd) >= 0) && ((pd) < PDRIVE_PINGROUP_COUNT))
+
+/* return 1 if a slew-rate rising/falling edge value is in range */
+#define pmux_pad_slw_isvalid(slw) (((slw) == PGRP_SLWF_NONE) || \
+				(((slw) >= 0) && ((slw) <= PGRP_SLWF_MAX)))
+
+/* return 1 if a driver output pull-up/down strength code value is in range */
+#define pmux_pad_drv_isvalid(drv) (((drv) == PGRP_DRVUP_NONE) || \
+				(((drv) >= 0) && ((drv) <= PGRP_DRVUP_MAX)))
+
+/* return 1 if a low-power mode value is in range */
+#define pmux_pad_lpmd_isvalid(lpm) (((lpm) == PGRP_LPMD_NONE) || \
+				(((lpm) >= 0) && ((lpm) <= PGRP_LPMD_X)))
+
+/* Defines a pin group cfg's low-power mode select */
+enum pgrp_lpmd {
+	PGRP_LPMD_X8 = 0,
+	PGRP_LPMD_X4,
+	PGRP_LPMD_X2,
+	PGRP_LPMD_X,
+	PGRP_LPMD_NONE = -1,
+};
+
+/* Defines whether a pin group cfg's schmidt is enabled or not */
+enum pgrp_schmt {
+	PGRP_SCHMT_DISABLE = 0,
+	PGRP_SCHMT_ENABLE = 1,
+};
+
+/* Defines whether a pin group cfg's high-speed mode is enabled or not */
+enum pgrp_hsm {
+	PGRP_HSM_DISABLE = 0,
+	PGRP_HSM_ENABLE = 1,
+};
+
+/*
+ * This defines the configuration for a pin group's pad control config
+ */
+struct padctrl_config {
+	enum pdrive_pingrp padgrp;	/* pin group PDRIVE_PINGRP_x */
+	int slwf;			/* falling edge slew         */
+	int slwr;			/* rising edge slew          */
+	int drvup;			/* pull-up drive strength    */
+	int drvdn;			/* pull-down drive strength  */
+	enum pgrp_lpmd lpmd;		/* low-power mode selection  */
+	enum pgrp_schmt schmt;		/* schmidt enable            */
+	enum pgrp_hsm hsm;		/* high-speed mode enable    */
+};
+
+/* t114 pin drive group and pin mux registers */
+#define PDRIVE_PINGROUP_OFFSET	(0x868 >> 2)
+#define PMUX_OFFSET	((0x3000 >> 2) - PDRIVE_PINGROUP_OFFSET - \
+				PDRIVE_PINGROUP_COUNT)
 struct pmux_tri_ctlr {
 	uint pmt_reserved0;		/* ABP_MISC_PP_ reserved offset 00 */
 	uint pmt_reserved1;		/* ABP_MISC_PP_ reserved offset 04 */
@@ -541,4 +605,12 @@
 /* Set a group of pins from a table */
 void pinmux_init(void);
 
-#endif  /* _TEGRA114_PINMUX_H_ */
+/**
+ * Set the GP pad configs
+ *
+ * @param config	List of config items
+ * @param len		Number of config items in list
+ */
+void padgrp_config_table(struct padctrl_config *config, int len);
+
+#endif	/* _TEGRA114_PINMUX_H_ */