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]);
+}