Tegra30: Cardhu: Add pad config tables/code based on pinmux code
authorTom Warren <twarren@nvidia.com>
Wed, 6 Mar 2013 23:16:22 +0000 (16:16 -0700)
committerTom Warren <twarren@nvidia.com>
Thu, 14 Mar 2013 18:06:43 +0000 (11:06 -0700)
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 <twarren@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
arch/arm/cpu/tegra30-common/pinmux.c
arch/arm/include/asm/arch-tegra30/gp_padctrl.h
arch/arm/include/asm/arch-tegra30/pinmux.h
board/nvidia/cardhu/cardhu.c
board/nvidia/cardhu/pinmux-config-cardhu.h

index 122665f..eecf058 100644 (file)
@@ -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,
@@ -38,6 +38,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) \
        {                                               \
@@ -504,3 +517,178 @@ void pinmux_config_table(struct pingroup_config *config, int len)
        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));
+
+       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]);
+}
index 9b383d0..23d184f 100644 (file)
@@ -56,4 +56,10 @@ struct apb_misc_gp_ctlr {
        u32     sdio1cfg;       /* 0xEC: APB_MISC_GP_SDIO1CFGPADCTRL */
 };
 
+/* SDMMC1/3 settings from section 24.6 of T30 TRM */
+#define SDIOCFG_DRVUP_SLWF     1
+#define SDIOCFG_DRVDN_SLWR     1
+#define SDIOCFG_DRVUP          0x2E
+#define SDIOCFG_DRVDN          0x2A
+
 #endif /* _TEGRA30_GP_PADCTRL_H_ */
index 341951b..a9e1b46 100644 (file)
@@ -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,4 +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 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_ */
index df4cb6b..08e9b7b 100644 (file)
@@ -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"
 
 /*
@@ -36,4 +37,7 @@ void pinmux_init(void)
 
        pinmux_config_table(unused_pins_lowpower,
                ARRAY_SIZE(unused_pins_lowpower));
+
+       /* Initialize any non-default pad configs (APB_MISC_GP regs) */
+       padgrp_config_table(cardhu_padctrl, ARRAY_SIZE(cardhu_padctrl));
 }
index 8428bba..51d2b94 100644 (file)
@@ -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,
                .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_ */