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, only SDIO1CFG is changed as per the TRM to work with
the SD-card slot on Cardhu.

Thanks to StephenW for the suggestion/original idea.

Signed-off-by: Tom Warren <[email protected]>
---
 arch/arm/cpu/tegra30-common/pinmux.c           |  210 +++++++++++++++++++++---
 arch/arm/include/asm/arch-tegra30/gp_padctrl.h |    8 +-
 arch/arm/include/asm/arch-tegra30/pinmux.h     |   68 ++++++++-
 board/nvidia/cardhu/cardhu.c                   |    6 +-
 board/nvidia/cardhu/pinmux-config-cardhu.h     |   21 ++-
 5 files changed, 278 insertions(+), 35 deletions(-)

diff --git a/arch/arm/cpu/tegra30-common/pinmux.c 
b/arch/arm/cpu/tegra30-common/pinmux.c
index 9ba0ec8..5a5862a 100644
--- a/arch/arm/cpu/tegra30-common/pinmux.c
+++ b/arch/arm/cpu/tegra30-common/pinmux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -39,6 +39,19 @@ struct tegra_pingroup_desc {
 #define PMUX_LOCK_SHIFT                7
 #define PMUX_IO_RESET_SHIFT    8
 
+#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) \
        {                                               \
@@ -506,28 +519,177 @@ void pinmux_config_table(struct pingroup_config *config, 
int len)
                pinmux_config_pingroup(&config[i]);
 }
 
-void pinmux_sdio_pad_cfg(void)
+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 apb_misc_gp_ctlr *const gpc =
-               (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
-       u32 val, padcfg, padmask;
-
-       /*
-        * Set pads as per T30 TRM, section 24.6.1.2.
-        * Slam both SDIO1CFG and SDIO3CFG in the APB_MISC_GP space
-        * since we can't parse the MMC cfg this early.
-        */
-       padcfg = (GP_SDIOCFG_DRVUP_SLWF | GP_SDIOCFG_DRVDN_SLWR | \
-               GP_SDIOCFG_DRVUP | GP_SDIOCFG_DRVDN);
-       padmask = 0x00000FFF;
-
-       val = readl(&gpc->sdio1cfg);
-       val &= padmask;
-       val |= padcfg;
-       writel(val, &gpc->sdio1cfg);
-
-       val = readl(&gpc->sdio3cfg);
-       val &= padmask;
-       val |= padcfg;
-       writel(val, &gpc->sdio3cfg);
+       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));
+
+       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));
+
+       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-tegra30/gp_padctrl.h 
b/arch/arm/include/asm/arch-tegra30/gp_padctrl.h
index 48b9a3b..23d184f 100644
--- a/arch/arm/include/asm/arch-tegra30/gp_padctrl.h
+++ b/arch/arm/include/asm/arch-tegra30/gp_padctrl.h
@@ -57,9 +57,9 @@ struct apb_misc_gp_ctlr {
 };
 
 /* SDMMC1/3 settings from section 24.6 of T30 TRM */
-#define GP_SDIOCFG_DRVUP_SLWF  (1 << 30)
-#define GP_SDIOCFG_DRVDN_SLWR  (1 << 28)
-#define GP_SDIOCFG_DRVUP       (0x2E << 20)
-#define GP_SDIOCFG_DRVDN       (0x2A << 12)
+#define SDIOCFG_DRVUP_SLWF     1
+#define SDIOCFG_DRVDN_SLWR     1
+#define SDIOCFG_DRVUP          0x2E
+#define SDIOCFG_DRVDN          0x2A
 
 #endif /* _TEGRA30_GP_PADCTRL_H_ */
diff --git a/arch/arm/include/asm/arch-tegra30/pinmux.h 
b/arch/arm/include/asm/arch-tegra30/pinmux.h
index 0a341b4..a9e1b46 100644
--- a/arch/arm/include/asm/arch-tegra30/pinmux.h
+++ b/arch/arm/include/asm/arch-tegra30/pinmux.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -531,6 +531,63 @@ enum pmux_vddio {
        PMUX_VDDIO_NONE
 };
 
+#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
+
+/* 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) >= 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) >= 0) && ((drv) <= PGRP_DRVUP_MAX))
+
+/* return 1 if a low-power mode value is in range */
+#define pmux_pad_lpmd_isvalid(lpm) (((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    */
+};
+
 /* t30 pin drive group and pin mux registers */
 #define PDRIVE_PINGROUP_OFFSET (0x868 >> 2)
 #define PMUX_OFFSET    ((0x3000 >> 2) - PDRIVE_PINGROUP_OFFSET - \
@@ -600,7 +657,12 @@ void pinmux_config_table(struct pingroup_config *config, 
int len);
 /* Set a group of pins from a table */
 void pinmux_init(void);
 
-/* Set the GP pad cfg as per the TRM for SDIO */
-void pinmux_sdio_pad_cfg(void);
+/**
+ * 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 /* _TEGRA30_PINMUX_H_ */
diff --git a/board/nvidia/cardhu/cardhu.c b/board/nvidia/cardhu/cardhu.c
index ae9afba..3544b41 100644
--- a/board/nvidia/cardhu/cardhu.c
+++ b/board/nvidia/cardhu/cardhu.c
@@ -1,5 +1,5 @@
 /*
- *  (C) Copyright 2010-2012
+ *  (C) Copyright 2010-2013
  *  NVIDIA Corporation <www.nvidia.com>
  *
  * See file CREDITS for list of people who contributed to this
@@ -23,6 +23,7 @@
 
 #include <common.h>
 #include <asm/arch/pinmux.h>
+#include <asm/arch/gp_padctrl.h>
 #include "pinmux-config-cardhu.h"
 #include <i2c.h>
 
@@ -41,7 +42,8 @@ void pinmux_init(void)
        pinmux_config_table(unused_pins_lowpower,
                ARRAY_SIZE(unused_pins_lowpower));
 
-       pinmux_sdio_pad_cfg();
+       /* Initialize any non-default pad configs (APB_MISC_GP regs) */
+       padgrp_config_table(cardhu_padctrl, ARRAY_SIZE(cardhu_padctrl));
 }
 
 #if defined(CONFIG_TEGRA_MMC)
diff --git a/board/nvidia/cardhu/pinmux-config-cardhu.h 
b/board/nvidia/cardhu/pinmux-config-cardhu.h
index 8428bba..51d2b94 100644
--- a/board/nvidia/cardhu/pinmux-config-cardhu.h
+++ b/board/nvidia/cardhu/pinmux-config-cardhu.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -53,6 +53,18 @@
                .ioreset        = PMUX_PIN_IO_RESET_##_ioreset  \
        }
 
+#define DEFAULT_PADCFG(_padgrp, _slwf, _slwr, _drvup, _drvdn, _lpmd, _schmt, 
_hsm) \
+       {                                                       \
+               .padgrp         = PDRIVE_PINGROUP_##_padgrp,    \
+               .slwf           = _slwf,                        \
+               .slwr           = _slwr,                        \
+               .drvup          = _drvup,                       \
+               .drvdn          = _drvdn,                       \
+               .lpmd           = PGRP_LPMD_##_lpmd,            \
+               .schmt          = PGRP_SCHMT_##_schmt,          \
+               .hsm            = PGRP_HSM_##_hsm,              \
+       }
+
 static struct pingroup_config tegra3_pinmux_common[] = {
        /* SDMMC1 pinmux */
        DEFAULT_PINMUX(SDMMC1_CLK, SDMMC1, NORMAL, NORMAL, INPUT),
@@ -326,4 +338,9 @@ static struct pingroup_config unused_pins_lowpower[] = {
        DEFAULT_PINMUX(GMI_DQS, NAND, NORMAL, TRISTATE, OUTPUT),
 };
 
-#endif /* _PINMUX_CONFIG_CARDHU_H_ */
+static struct padctrl_config cardhu_padctrl[] = {
+       /* (_padgrp, _slwf, _slwr, _drvup, _drvdn, _lpmd, _schmt, _hsm) */
+       DEFAULT_PADCFG(SDIO1, SDIOCFG_DRVUP_SLWF, SDIOCFG_DRVDN_SLWR, \
+               SDIOCFG_DRVUP, SDIOCFG_DRVDN, NONE, DISABLE, DISABLE),
+};
+#endif /* _PINMUX_CONFIG_CARDHU_H_ */
-- 
1.7.0.4

_______________________________________________
U-Boot mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to