summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Makefile2
-rw-r--r--arch/arm/mach-tegra/board2.c22
-rw-r--r--arch/arm/mach-tegra/gpu.c11
-rw-r--r--arch/arm/mach-tegra/tegra124/Makefile1
-rw-r--r--arch/arm/mach-tegra/tegra124/xusb-padctl.c431
-rw-r--r--arch/arm/mach-tegra/tegra210/Kconfig10
-rw-r--r--arch/arm/mach-tegra/tegra210/Makefile1
-rw-r--r--arch/arm/mach-tegra/tegra210/clock.c179
-rw-r--r--arch/arm/mach-tegra/tegra210/xusb-padctl.c248
-rw-r--r--arch/arm/mach-tegra/xusb-padctl-common.c305
-rw-r--r--arch/arm/mach-tegra/xusb-padctl-common.h101
-rw-r--r--arch/arm/mach-tegra/xusb-padctl-dummy.c (renamed from arch/arm/mach-tegra/xusb-padctl.c)0
12 files changed, 687 insertions, 624 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 98431a91f8..2be6ef41ff 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -23,7 +23,7 @@ obj-y += clock.o
obj-y += lowlevel_init.o
obj-y += pinmux-common.o
obj-y += powergate.o
-obj-y += xusb-padctl.o
+obj-y += xusb-padctl-dummy.o
obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
obj-$(CONFIG_TEGRA_GPU) += gpu.o
obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c
index 8ecc67459a..8ba143d996 100644
--- a/arch/arm/mach-tegra/board2.c
+++ b/arch/arm/mach-tegra/board2.c
@@ -128,7 +128,7 @@ int board_init(void)
clock_init();
clock_verify();
- config_gpu();
+ tegra_gpu_config();
#ifdef CONFIG_TEGRA_SPI
pin_mux_spi();
@@ -403,3 +403,23 @@ ulong board_get_usable_ram_top(ulong total_size)
{
return CONFIG_SYS_SDRAM_BASE + usable_ram_size_below_4g();
}
+
+/*
+ * This function is called right before the kernel is booted. "blob" is the
+ * device tree that will be passed to the kernel.
+ */
+int ft_system_setup(void *blob, bd_t *bd)
+{
+ const char *gpu_path =
+#if defined(CONFIG_TEGRA124) || defined(CONFIG_TEGRA210)
+ "/gpu@0,57000000";
+#else
+ NULL;
+#endif
+
+ /* Enable GPU node if GPU setup has been performed */
+ if (gpu_path != NULL)
+ return tegra_gpu_enable_node(blob, gpu_path);
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/gpu.c b/arch/arm/mach-tegra/gpu.c
index 4ea046d3e5..c7d705d8ef 100644
--- a/arch/arm/mach-tegra/gpu.c
+++ b/arch/arm/mach-tegra/gpu.c
@@ -25,7 +25,7 @@
static bool _configured;
-void config_gpu(void)
+void tegra_gpu_config(void)
{
struct mc_ctlr *mc = (struct mc_ctlr *)NV_PA_MC_BASE;
@@ -41,18 +41,13 @@ void config_gpu(void)
_configured = true;
}
-bool vpr_configured(void)
-{
- return _configured;
-}
-
#if defined(CONFIG_OF_LIBFDT)
-int gpu_enable_node(void *blob, const char *gpupath)
+int tegra_gpu_enable_node(void *blob, const char *gpupath)
{
int offset;
- if (vpr_configured()) {
+ if (_configured) {
offset = fdt_path_offset(blob, gpupath);
if (offset > 0) {
fdt_status_okay(blob, offset);
diff --git a/arch/arm/mach-tegra/tegra124/Makefile b/arch/arm/mach-tegra/tegra124/Makefile
index f577f459be..c00de6151e 100644
--- a/arch/arm/mach-tegra/tegra124/Makefile
+++ b/arch/arm/mach-tegra/tegra124/Makefile
@@ -11,6 +11,7 @@ obj-y += clock.o
obj-y += funcmux.o
obj-y += pinmux.o
obj-y += xusb-padctl.o
+obj-y += ../xusb-padctl-common.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ARMV7_NONSEC) += psci.o
diff --git a/arch/arm/mach-tegra/tegra124/xusb-padctl.c b/arch/arm/mach-tegra/tegra124/xusb-padctl.c
index 43af883f2c..76af924b94 100644
--- a/arch/arm/mach-tegra/tegra124/xusb-padctl.c
+++ b/arch/arm/mach-tegra/tegra124/xusb-padctl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0
*/
@@ -8,13 +8,8 @@
#include <common.h>
#include <errno.h>
-#include <fdtdec.h>
-#include <malloc.h>
-#include <asm/io.h>
-
-#include <asm/arch/clock.h>
-#include <asm/arch-tegra/xusb-padctl.h>
+#include "../xusb-padctl-common.h"
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
@@ -83,18 +78,6 @@ static const unsigned int tegra124_pci_functions[] = {
TEGRA124_FUNC_RSVD,
};
-struct tegra_xusb_padctl_lane {
- const char *name;
-
- unsigned int offset;
- unsigned int shift;
- unsigned int mask;
- unsigned int iddq;
-
- const unsigned int *funcs;
- unsigned int num_funcs;
-};
-
#define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs) \
{ \
.name = _name, \
@@ -121,74 +104,6 @@ static const struct tegra_xusb_padctl_lane tegra124_lanes[] = {
TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci),
};
-struct tegra_xusb_phy_ops {
- int (*prepare)(struct tegra_xusb_phy *phy);
- int (*enable)(struct tegra_xusb_phy *phy);
- int (*disable)(struct tegra_xusb_phy *phy);
- int (*unprepare)(struct tegra_xusb_phy *phy);
-};
-
-struct tegra_xusb_phy {
- const struct tegra_xusb_phy_ops *ops;
-
- struct tegra_xusb_padctl *padctl;
-};
-
-struct tegra_xusb_padctl_pin {
- const struct tegra_xusb_padctl_lane *lane;
-
- unsigned int func;
- int iddq;
-};
-
-#define MAX_GROUPS 3
-#define MAX_PINS 6
-
-struct tegra_xusb_padctl_group {
- const char *name;
-
- const char *pins[MAX_PINS];
- unsigned int num_pins;
-
- const char *func;
- int iddq;
-};
-
-struct tegra_xusb_padctl_config {
- const char *name;
-
- struct tegra_xusb_padctl_group groups[MAX_GROUPS];
- unsigned int num_groups;
-};
-
-struct tegra_xusb_padctl {
- struct fdt_resource regs;
-
- unsigned int enable;
-
- struct tegra_xusb_phy phys[2];
-
- const struct tegra_xusb_padctl_lane *lanes;
- unsigned int num_lanes;
-
- const char *const *functions;
- unsigned int num_functions;
-
- struct tegra_xusb_padctl_config config;
-};
-
-static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
- unsigned long offset)
-{
- return readl(padctl->regs.start + offset);
-}
-
-static inline void padctl_writel(struct tegra_xusb_padctl *padctl,
- u32 value, unsigned long offset)
-{
- writel(value, padctl->regs.start + offset);
-}
-
static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
{
u32 value;
@@ -220,7 +135,7 @@ static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
u32 value;
if (padctl->enable == 0) {
- error("tegra-xusb-padctl: unbalanced enable/disable");
+ error("unbalanced enable/disable");
return 0;
}
@@ -380,329 +295,27 @@ static const struct tegra_xusb_phy_ops sata_phy_ops = {
.unprepare = phy_unprepare,
};
-static struct tegra_xusb_padctl *padctl = &(struct tegra_xusb_padctl) {
- .phys = {
- [0] = {
- .ops = &pcie_phy_ops,
- },
- [1] = {
- .ops = &sata_phy_ops,
- },
+static struct tegra_xusb_phy tegra124_phys[] = {
+ {
+ .type = TEGRA_XUSB_PADCTL_PCIE,
+ .ops = &pcie_phy_ops,
+ .padctl = &padctl,
+ },
+ {
+ .type = TEGRA_XUSB_PADCTL_SATA,
+ .ops = &sata_phy_ops,
+ .padctl = &padctl,
},
};
-static const struct tegra_xusb_padctl_lane *
-tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name)
-{
- unsigned int i;
-
- for (i = 0; i < padctl->num_lanes; i++)
- if (strcmp(name, padctl->lanes[i].name) == 0)
- return &padctl->lanes[i];
-
- return NULL;
-}
-
-static int
-tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl,
- struct tegra_xusb_padctl_group *group,
- const void *fdt, int node)
-{
- unsigned int i;
- int len, err;
-
- group->name = fdt_get_name(fdt, node, &len);
-
- len = fdt_count_strings(fdt, node, "nvidia,lanes");
- if (len < 0) {
- error("tegra-xusb-padctl: failed to parse \"nvidia,lanes\" property");
- return -EINVAL;
- }
-
- group->num_pins = len;
-
- for (i = 0; i < group->num_pins; i++) {
- err = fdt_get_string_index(fdt, node, "nvidia,lanes", i,
- &group->pins[i]);
- if (err < 0) {
- error("tegra-xusb-padctl: failed to read string from \"nvidia,lanes\" property");
- return -EINVAL;
- }
- }
-
- group->num_pins = len;
-
- err = fdt_get_string(fdt, node, "nvidia,function", &group->func);
- if (err < 0) {
- error("tegra-xusb-padctl: failed to parse \"nvidia,func\" property");
- return -EINVAL;
- }
-
- group->iddq = fdtdec_get_int(fdt, node, "nvidia,iddq", -1);
-
- return 0;
-}
-
-static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl,
- const char *name)
-{
- unsigned int i;
-
- for (i = 0; i < padctl->num_functions; i++)
- if (strcmp(name, padctl->functions[i]) == 0)
- return i;
-
- return -ENOENT;
-}
-
-static int
-tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl,
- const struct tegra_xusb_padctl_lane *lane,
- const char *name)
-{
- unsigned int i;
- int func;
-
- func = tegra_xusb_padctl_find_function(padctl, name);
- if (func < 0)
- return func;
-
- for (i = 0; i < lane->num_funcs; i++)
- if (lane->funcs[i] == func)
- return i;
-
- return -ENOENT;
-}
-
-static int
-tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl,
- const struct tegra_xusb_padctl_group *group)
-{
- unsigned int i;
-
- for (i = 0; i < group->num_pins; i++) {
- const struct tegra_xusb_padctl_lane *lane;
- unsigned int func;
- u32 value;
-
- lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]);
- if (!lane) {
- error("tegra-xusb-padctl: no lane for pin %s",
- group->pins[i]);
- continue;
- }
-
- func = tegra_xusb_padctl_lane_find_function(padctl, lane,
- group->func);
- if (func < 0) {
- error("tegra-xusb-padctl: function %s invalid for lane %s: %d",
- group->func, lane->name, func);
- continue;
- }
-
- value = padctl_readl(padctl, lane->offset);
-
- /* set pin function */
- value &= ~(lane->mask << lane->shift);
- value |= func << lane->shift;
-
- /*
- * Set IDDQ if supported on the lane and specified in the
- * configuration.
- */
- if (lane->iddq > 0 && group->iddq >= 0) {
- if (group->iddq != 0)
- value &= ~(1 << lane->iddq);
- else
- value |= 1 << lane->iddq;
- }
-
- padctl_writel(padctl, value, lane->offset);
- }
-
- return 0;
-}
-
-static int
-tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl,
- struct tegra_xusb_padctl_config *config)
-{
- unsigned int i;
-
- for (i = 0; i < config->num_groups; i++) {
- const struct tegra_xusb_padctl_group *group;
- int err;
-
- group = &config->groups[i];
-
- err = tegra_xusb_padctl_group_apply(padctl, group);
- if (err < 0) {
- error("tegra-xusb-padctl: failed to apply group %s: %d",
- group->name, err);
- continue;
- }
- }
-
- return 0;
-}
-
-static int
-tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl,
- struct tegra_xusb_padctl_config *config,
- const void *fdt, int node)
-{
- int subnode;
-
- config->name = fdt_get_name(fdt, node, NULL);
-
- fdt_for_each_subnode(fdt, subnode, node) {
- struct tegra_xusb_padctl_group *group;
- int err;
-
- group = &config->groups[config->num_groups];
-
- err = tegra_xusb_padctl_group_parse_dt(padctl, group, fdt,
- subnode);
- if (err < 0) {
- error("tegra-xusb-padctl: failed to parse group %s",
- group->name);
- return err;
- }
-
- config->num_groups++;
- }
-
- return 0;
-}
-
-static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
- const void *fdt, int node)
-{
- int subnode, err;
-
- err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs);
- if (err < 0) {
- error("tegra-xusb-padctl: registers not found");
- return err;
- }
-
- fdt_for_each_subnode(fdt, subnode, node) {
- struct tegra_xusb_padctl_config *config = &padctl->config;
-
- err = tegra_xusb_padctl_config_parse_dt(padctl, config, fdt,
- subnode);
- if (err < 0) {
- error("tegra-xusb-padctl: failed to parse entry %s: %d",
- config->name, err);
- continue;
- }
- }
-
- return 0;
-}
-
-static int process_nodes(const void *fdt, int nodes[], unsigned int count)
-{
- unsigned int i;
-
- for (i = 0; i < count; i++) {
- enum fdt_compat_id id;
- int err;
-
- if (!fdtdec_get_is_enabled(fdt, nodes[i]))
- continue;
-
- id = fdtdec_lookup(fdt, nodes[i]);
- switch (id) {
- case COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL:
- break;
-
- default:
- error("tegra-xusb-padctl: unsupported compatible: %s",
- fdtdec_get_compatible(id));
- continue;
- }
-
- padctl->num_lanes = ARRAY_SIZE(tegra124_lanes);
- padctl->lanes = tegra124_lanes;
-
- padctl->num_functions = ARRAY_SIZE(tegra124_functions);
- padctl->functions = tegra124_functions;
-
- err = tegra_xusb_padctl_parse_dt(padctl, fdt, nodes[i]);
- if (err < 0) {
- error("tegra-xusb-padctl: failed to parse DT: %d",
- err);
- continue;
- }
-
- /* deassert XUSB padctl reset */
- reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
-
- err = tegra_xusb_padctl_config_apply(padctl, &padctl->config);
- if (err < 0) {
- error("tegra-xusb-padctl: failed to apply pinmux: %d",
- err);
- continue;
- }
-
- /* only a single instance is supported */
- break;
- }
-
- return 0;
-}
-
-struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
-{
- struct tegra_xusb_phy *phy = NULL;
-
- switch (type) {
- case TEGRA_XUSB_PADCTL_PCIE:
- phy = &padctl->phys[0];
- phy->padctl = padctl;
- break;
-
- case TEGRA_XUSB_PADCTL_SATA:
- phy = &padctl->phys[1];
- phy->padctl = padctl;
- break;
- }
-
- return phy;
-}
-
-int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->prepare)
- return phy->ops->prepare(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->enable)
- return phy->ops->enable(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->disable)
- return phy->ops->disable(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->unprepare)
- return phy->ops->unprepare(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
+static const struct tegra_xusb_padctl_soc tegra124_socdata = {
+ .lanes = tegra124_lanes,
+ .num_lanes = ARRAY_SIZE(tegra124_lanes),
+ .functions = tegra124_functions,
+ .num_functions = ARRAY_SIZE(tegra124_functions),
+ .phys = tegra124_phys,
+ .num_phys = ARRAY_SIZE(tegra124_phys),
+};
void tegra_xusb_padctl_init(const void *fdt)
{
@@ -711,6 +324,6 @@ void tegra_xusb_padctl_init(const void *fdt)
count = fdtdec_find_aliases_for_id(fdt, "padctl",
COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
nodes, ARRAY_SIZE(nodes));
- if (process_nodes(fdt, nodes, count))
+ if (tegra_xusb_process_nodes(fdt, nodes, count, &tegra124_socdata))
return;
}
diff --git a/arch/arm/mach-tegra/tegra210/Kconfig b/arch/arm/mach-tegra/tegra210/Kconfig
index b07363a4c3..055fb124d8 100644
--- a/arch/arm/mach-tegra/tegra210/Kconfig
+++ b/arch/arm/mach-tegra/tegra210/Kconfig
@@ -19,12 +19,12 @@ config TARGET_P2371_0000
a GPIO expansion header, and an analog audio jack.
config TARGET_P2371_2180
- bool "NVIDIA Tegra210 P2371-2180 board"
+ bool "NVIDIA Tegra210 P2371-2180 (Jetson TX1) board"
help
- P2371-2180 is a P2180 CPU board married to a P2597 I/O board. The
- combination contains SoC, DRAM, eMMC, SD card slot, HDMI, USB
- micro-B port, Ethernet via USB3, USB3 host port, SATA, PCIe, and
- two GPIO expansion headers.
+ P2371-2180 (Jetson TX1 developer kit) is a P2180 CPU board married
+ to a P2597 I/O board. The combination contains SoC, DRAM, eMMC, SD
+ card slot, HDMI, USB micro-B port, Ethernet via USB3, USB3 host
+ port, SATA, PCIe, and two GPIO expansion headers.
config TARGET_P2571
bool "NVIDIA Tegra210 P2571 base board"
diff --git a/arch/arm/mach-tegra/tegra210/Makefile b/arch/arm/mach-tegra/tegra210/Makefile
index 1fb8d1ac74..b6012fc7ba 100644
--- a/arch/arm/mach-tegra/tegra210/Makefile
+++ b/arch/arm/mach-tegra/tegra210/Makefile
@@ -9,3 +9,4 @@ obj-y += clock.o
obj-y += funcmux.o
obj-y += pinmux.o
obj-y += xusb-padctl.o
+obj-y += ../xusb-padctl-common.o
diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c
index 6d75d371cb..df92bdce88 100644
--- a/arch/arm/mach-tegra/tegra210/clock.c
+++ b/arch/arm/mach-tegra/tegra210/clock.c
@@ -8,6 +8,7 @@
/* Tegra210 Clock control functions */
#include <common.h>
+#include <errno.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/sysctr.h>
@@ -1030,6 +1031,59 @@ void arch_timer_init(void)
debug("%s: TSC CNTCR = 0x%08X\n", __func__, val);
}
+#define PLLREFE_MISC 0x4c8
+#define PLLREFE_MISC_LOCK BIT(27)
+#define PLLREFE_MISC_IDDQ BIT(24)
+
+#define PLLREFE_BASE 0x4c4
+#define PLLREFE_BASE_BYPASS BIT(31)
+#define PLLREFE_BASE_ENABLE BIT(30)
+#define PLLREFE_BASE_REF_DIS BIT(29)
+#define PLLREFE_BASE_KCP(kcp) (((kcp) & 0x3) << 27)
+#define PLLREFE_BASE_KVCO BIT(26)
+#define PLLREFE_BASE_DIVP(p) (((p) & 0x1f) << 16)
+#define PLLREFE_BASE_DIVN(n) (((n) & 0xff) << 8)
+#define PLLREFE_BASE_DIVM(m) (((m) & 0xff) << 0)
+
+static int tegra_pllref_enable(void)
+{
+ u32 value;
+ unsigned long start;
+
+ /*
+ * This sequence comes from Tegra X1 TRM section "Cold Boot, with no
+ * Recovery Mode or Boot from USB", sub-section "PLLREFE".
+ */
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLREFE_MISC);
+ value &= ~PLLREFE_MISC_IDDQ;
+ writel(value, NV_PA_CLK_RST_BASE + PLLREFE_MISC);
+
+ udelay(5);
+
+ value = PLLREFE_BASE_ENABLE |
+ PLLREFE_BASE_KCP(0) |
+ PLLREFE_BASE_DIVP(0) |
+ PLLREFE_BASE_DIVN(0x41) |
+ PLLREFE_BASE_DIVM(4);
+ writel(value, NV_PA_CLK_RST_BASE + PLLREFE_BASE);
+
+ debug("waiting for pllrefe lock\n");
+ start = get_timer(0);
+ while (get_timer(start) < 250) {
+ value = readl(NV_PA_CLK_RST_BASE + PLLREFE_MISC);
+ if (value & PLLREFE_MISC_LOCK)
+ break;
+ }
+ if (!(value & PLLREFE_MISC_LOCK)) {
+ debug(" timeout\n");
+ return -ETIMEDOUT;
+ }
+ debug(" done\n");
+
+ return 0;
+}
+
#define PLLE_SS_CNTL 0x68
#define PLLE_SS_CNTL_SSCINCINTR(x) (((x) & 0x3f) << 24)
#define PLLE_SS_CNTL_SSCINC(x) (((x) & 0xff) << 16)
@@ -1041,100 +1095,131 @@ void arch_timer_init(void)
#define PLLE_SS_CNTL_SSCMAX(x) (((x) & 0x1ff) << 0)
#define PLLE_BASE 0x0e8
-#define PLLE_BASE_ENABLE (1 << 30)
-#define PLLE_BASE_LOCK_OVERRIDE (1 << 29)
-#define PLLE_BASE_PLDIV_CML(x) (((x) & 0xf) << 24)
+#define PLLE_BASE_ENABLE (1 << 31)
+#define PLLE_BASE_PLDIV_CML(x) (((x) & 0x1f) << 24)
#define PLLE_BASE_NDIV(x) (((x) & 0xff) << 8)
#define PLLE_BASE_MDIV(x) (((x) & 0xff) << 0)
#define PLLE_MISC 0x0ec
#define PLLE_MISC_IDDQ_SWCTL (1 << 14)
-#define PLLE_MISC_IDDQ_OVERRIDE (1 << 13)
-#define PLLE_MISC_LOCK_ENABLE (1 << 9)
-#define PLLE_MISC_PTS (1 << 8)
-#define PLLE_MISC_VREG_BG_CTRL(x) (((x) & 0x3) << 4)
+#define PLLE_MISC_IDDQ_OVERRIDE_VALUE (1 << 13)
+#define PLLE_MISC_LOCK (1 << 11)
+#define PLLE_MISC_KCP(x) (((x) & 0x3) << 6)
#define PLLE_MISC_VREG_CTRL(x) (((x) & 0x3) << 2)
+#define PLLE_MISC_KVCO (1 << 0)
#define PLLE_AUX 0x48c
+#define PLLE_AUX_SS_SEQ_INCLUDE (1 << 31)
+#define PLLE_AUX_REF_SEL_PLLREFE (1 << 28)
#define PLLE_AUX_SEQ_ENABLE (1 << 24)
+#define PLLE_AUX_SS_SWCTL (1 << 6)
#define PLLE_AUX_ENABLE_SWCTL (1 << 4)
+#define PLLE_AUX_USE_LOCKDET (1 << 3)
int tegra_plle_enable(void)
{
- unsigned int m = 1, n = 200, cpcon = 13;
u32 value;
+ unsigned long start;
- value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
- value &= ~PLLE_BASE_LOCK_OVERRIDE;
- writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
+ /* PLLREF feeds PLLE */
+ tegra_pllref_enable();
+
+ /*
+ * This sequence comes from Tegra X1 TRM section "Cold Boot, with no
+ * Recovery Mode or Boot from USB", sub-section "PLLEs".
+ */
+
+ /* 1. Select XTAL as the source */
value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX);
- value |= PLLE_AUX_ENABLE_SWCTL;
- value &= ~PLLE_AUX_SEQ_ENABLE;
+ value &= ~PLLE_AUX_REF_SEL_PLLREFE;
writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
- udelay(1);
-
value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
- value |= PLLE_MISC_IDDQ_SWCTL;
- value &= ~PLLE_MISC_IDDQ_OVERRIDE;
- value |= PLLE_MISC_LOCK_ENABLE;
- value |= PLLE_MISC_PTS;
- value |= PLLE_MISC_VREG_BG_CTRL(3);
- value |= PLLE_MISC_VREG_CTRL(2);
+ value &= ~PLLE_MISC_IDDQ_OVERRIDE_VALUE;
writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+ /* 2. Wait 5 us */
udelay(5);
- value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
- value |= PLLE_SS_CNTL_SSCBYP | PLLE_SS_CNTL_INTERP_RESET |
- PLLE_SS_CNTL_BYPASS_SS;
- writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+ /*
+ * 3. Program the following registers to generate a low jitter 100MHz
+ * clock.
+ */
value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
- value &= ~PLLE_BASE_PLDIV_CML(0xf);
+ value &= ~PLLE_BASE_PLDIV_CML(0x1f);
value &= ~PLLE_BASE_NDIV(0xff);
value &= ~PLLE_BASE_MDIV(0xff);
- value |= PLLE_BASE_PLDIV_CML(cpcon);
- value |= PLLE_BASE_NDIV(n);
- value |= PLLE_BASE_MDIV(m);
+ value |= PLLE_BASE_PLDIV_CML(0xe);
+ value |= PLLE_BASE_NDIV(0x7d);
+ value |= PLLE_BASE_MDIV(2);
writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
- udelay(1);
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ value &= ~PLLE_MISC_KCP(3);
+ value &= ~PLLE_MISC_VREG_CTRL(3);
+ value &= ~PLLE_MISC_KVCO;
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
value |= PLLE_BASE_ENABLE;
writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
- /* wait for lock */
- udelay(300);
-
- value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
- value &= ~PLLE_SS_CNTL_SSCINVERT;
- value &= ~PLLE_SS_CNTL_SSCCENTER;
-
- value &= ~PLLE_SS_CNTL_SSCINCINTR(0x3f);
- value &= ~PLLE_SS_CNTL_SSCINC(0xff);
- value &= ~PLLE_SS_CNTL_SSCMAX(0x1ff);
+ /* 4. Wait for LOCK */
- value |= PLLE_SS_CNTL_SSCINCINTR(0x20);
- value |= PLLE_SS_CNTL_SSCINC(0x01);
- value |= PLLE_SS_CNTL_SSCMAX(0x25);
+ debug("waiting for plle lock\n");
+ start = get_timer(0);
+ while (get_timer(start) < 250) {
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ if (value & PLLE_MISC_LOCK)
+ break;
+ }
+ if (!(value & PLLE_MISC_LOCK)) {
+ debug(" timeout\n");
+ return -ETIMEDOUT;
+ }
+ debug(" done\n");
- writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+ /* 5. Enable SSA */
value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
- value &= ~PLLE_SS_CNTL_SSCBYP;
+ value &= ~PLLE_SS_CNTL_SSCINC(0xff);
+ value |= PLLE_SS_CNTL_SSCINC(1);
+ value &= ~PLLE_SS_CNTL_SSCINCINTR(0x3f);
+ value |= PLLE_SS_CNTL_SSCINCINTR(0x23);
+ value &= ~PLLE_SS_CNTL_SSCMAX(0x1fff);
+ value |= PLLE_SS_CNTL_SSCMAX(0x21);
+ value &= ~PLLE_SS_CNTL_SSCINVERT;
+ value &= ~PLLE_SS_CNTL_SSCCENTER;
value &= ~PLLE_SS_CNTL_BYPASS_SS;
+ value &= ~PLLE_SS_CNTL_SSCBYP;
writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
- udelay(1);
+ /* 6. Wait 300 ns */
- value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+ udelay(1);
value &= ~PLLE_SS_CNTL_INTERP_RESET;
writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
+ /* 7. Enable HW power sequencer for PLLE */
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
+ value &= ~PLLE_MISC_IDDQ_SWCTL;
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
+
+ value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX);
+ value &= ~PLLE_AUX_SS_SWCTL;
+ value &= ~PLLE_AUX_ENABLE_SWCTL;
+ value |= PLLE_AUX_SS_SEQ_INCLUDE;
+ value |= PLLE_AUX_USE_LOCKDET;
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
+
+ /* 8. Wait 1 us */
+
udelay(1);
+ value |= PLLE_AUX_SEQ_ENABLE;
+ writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
return 0;
}
diff --git a/arch/arm/mach-tegra/tegra210/xusb-padctl.c b/arch/arm/mach-tegra/tegra210/xusb-padctl.c
index 3c10a96aa3..9ec93e7c4c 100644
--- a/arch/arm/mach-tegra/tegra210/xusb-padctl.c
+++ b/arch/arm/mach-tegra/tegra210/xusb-padctl.c
@@ -8,51 +8,82 @@
#include <common.h>
#include <errno.h>
-#include <fdtdec.h>
-#include <malloc.h>
-#include <asm/io.h>
+#include "../xusb-padctl-common.h"
#include <asm/arch/clock.h>
-#include <asm/arch-tegra/xusb-padctl.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
-struct tegra_xusb_phy_ops {
- int (*prepare)(struct tegra_xusb_phy *phy);
- int (*enable)(struct tegra_xusb_phy *phy);
- int (*disable)(struct tegra_xusb_phy *phy);
- int (*unprepare)(struct tegra_xusb_phy *phy);
+enum tegra210_function {
+ TEGRA210_FUNC_SNPS,
+ TEGRA210_FUNC_XUSB,
+ TEGRA210_FUNC_UART,
+ TEGRA210_FUNC_PCIE_X1,
+ TEGRA210_FUNC_PCIE_X4,
+ TEGRA210_FUNC_USB3,
+ TEGRA210_FUNC_SATA,
+ TEGRA210_FUNC_RSVD,
};
-struct tegra_xusb_phy {
- const struct tegra_xusb_phy_ops *ops;
-
- struct tegra_xusb_padctl *padctl;
+static const char *const tegra210_functions[] = {
+ "snps",
+ "xusb",
+ "uart",
+ "pcie-x1",
+ "pcie-x4",
+ "usb3",
+ "sata",
+ "rsvd",
};
-struct tegra_xusb_padctl {
- struct fdt_resource regs;
+static const unsigned int tegra210_otg_functions[] = {
+ TEGRA210_FUNC_SNPS,
+ TEGRA210_FUNC_XUSB,
+ TEGRA210_FUNC_UART,
+ TEGRA210_FUNC_RSVD,
+};
- unsigned int enable;
+static const unsigned int tegra210_usb_functions[] = {
+ TEGRA210_FUNC_SNPS,
+ TEGRA210_FUNC_XUSB,
+};
- struct tegra_xusb_phy phys[2];
+static const unsigned int tegra210_pci_functions[] = {
+ TEGRA210_FUNC_PCIE_X1,
+ TEGRA210_FUNC_USB3,
+ TEGRA210_FUNC_SATA,
+ TEGRA210_FUNC_PCIE_X4,
};
-static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
- unsigned long offset)
-{
- u32 value = readl(padctl->regs.start + offset);
- debug("padctl: %08lx > %08x\n", offset, value);
- return value;
-}
+#define TEGRA210_LANE(_name, _offset, _shift, _mask, _iddq, _funcs) \
+ { \
+ .name = _name, \
+ .offset = _offset, \
+ .shift = _shift, \
+ .mask = _mask, \
+ .iddq = _iddq, \
+ .num_funcs = ARRAY_SIZE(tegra210_##_funcs##_functions), \
+ .funcs = tegra210_##_funcs##_functions, \
+ }
-static inline void padctl_writel(struct tegra_xusb_padctl *padctl,
- u32 value, unsigned long offset)
-{
- debug("padctl: %08lx < %08x\n", offset, value);
- writel(value, padctl->regs.start + offset);
-}
+static const struct tegra_xusb_padctl_lane tegra210_lanes[] = {
+ TEGRA210_LANE("otg-0", 0x004, 0, 0x3, 0, otg),
+ TEGRA210_LANE("otg-1", 0x004, 2, 0x3, 0, otg),
+ TEGRA210_LANE("otg-2", 0x004, 4, 0x3, 0, otg),
+ TEGRA210_LANE("otg-3", 0x004, 6, 0x3, 0, otg),
+ TEGRA210_LANE("usb2-bias", 0x004, 18, 0x3, 0, otg),
+ TEGRA210_LANE("hsic-0", 0x004, 14, 0x1, 0, usb),
+ TEGRA210_LANE("hsic-1", 0x004, 15, 0x1, 0, usb),
+ TEGRA210_LANE("pcie-0", 0x028, 12, 0x3, 1, pci),
+ TEGRA210_LANE("pcie-1", 0x028, 14, 0x3, 2, pci),
+ TEGRA210_LANE("pcie-2", 0x028, 16, 0x3, 3, pci),
+ TEGRA210_LANE("pcie-3", 0x028, 18, 0x3, 4, pci),
+ TEGRA210_LANE("pcie-4", 0x028, 20, 0x3, 5, pci),
+ TEGRA210_LANE("pcie-5", 0x028, 22, 0x3, 6, pci),
+ TEGRA210_LANE("pcie-6", 0x028, 24, 0x3, 7, pci),
+ TEGRA210_LANE("sata-0", 0x028, 30, 0x3, 8, pci),
+};
#define XUSB_PADCTL_ELPG_PROGRAM 0x024
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
@@ -248,7 +279,10 @@ static int pcie_phy_enable(struct tegra_xusb_phy *phy)
if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE)
break;
}
-
+ if (!(value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE)) {
+ debug(" timeout\n");
+ return -ETIMEDOUT;
+ }
debug(" done\n");
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
@@ -264,7 +298,10 @@ static int pcie_phy_enable(struct tegra_xusb_phy *phy)
if ((value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE) == 0)
break;
}
-
+ if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL2_CAL_DONE) {
+ debug(" timeout\n");
+ return -ETIMEDOUT;
+ }
debug(" done\n");
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL1);
@@ -279,7 +316,10 @@ static int pcie_phy_enable(struct tegra_xusb_phy *phy)
if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL1_LOCKDET_STATUS)
break;
}
-
+ if (!(value & XUSB_PADCTL_UPHY_PLL_P0_CTL1_LOCKDET_STATUS)) {
+ debug(" timeout\n");
+ return -ETIMEDOUT;
+ }
debug(" done\n");
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
@@ -295,7 +335,10 @@ static int pcie_phy_enable(struct tegra_xusb_phy *phy)
if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE)
break;
}
-
+ if (!(value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE)) {
+ debug(" timeout\n");
+ return -ETIMEDOUT;
+ }
debug(" done\n");
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
@@ -310,7 +353,10 @@ static int pcie_phy_enable(struct tegra_xusb_phy *phy)
if ((value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE) == 0)
break;
}
-
+ if (value & XUSB_PADCTL_UPHY_PLL_P0_CTL8_RCAL_DONE) {
+ debug(" timeout\n");
+ return -ETIMEDOUT;
+ }
debug(" done\n");
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL8);
@@ -358,120 +404,22 @@ static const struct tegra_xusb_phy_ops pcie_phy_ops = {
.unprepare = phy_unprepare,
};
-static struct tegra_xusb_padctl *padctl = &(struct tegra_xusb_padctl) {
- .phys = {
- [0] = {
- .ops = &pcie_phy_ops,
- },
+static struct tegra_xusb_phy tegra210_phys[] = {
+ {
+ .type = TEGRA_XUSB_PADCTL_PCIE,
+ .ops = &pcie_phy_ops,
+ .padctl = &padctl,
},
};
-static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
- const void *fdt, int node)
-{
- int err;
-
- err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs);
- if (err < 0) {
- error("registers not found");
- return err;
- }
-
- debug("regs: %pa-%pa\n", &padctl->regs.start,
- &padctl->regs.end);
-
- return 0;
-}
-
-static int process_nodes(const void *fdt, int nodes[], unsigned int count)
-{
- unsigned int i;
- int err;
-
- debug("> %s(fdt=%p, nodes=%p, count=%u)\n", __func__, fdt, nodes,
- count);
-
- for (i = 0; i < count; i++) {
- enum fdt_compat_id id;
-
- if (!fdtdec_get_is_enabled(fdt, nodes[i]))
- continue;
-
- id = fdtdec_lookup(fdt, nodes[i]);
- switch (id) {
- case COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL:
- case COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL:
- break;
-
- default:
- error("unsupported compatible: %s",
- fdtdec_get_compatible(id));
- continue;
- }
-
- err = tegra_xusb_padctl_parse_dt(padctl, fdt, nodes[i]);
- if (err < 0) {
- error("failed to parse DT: %d",
- err);
- continue;
- }
-
- /* deassert XUSB padctl reset */
- reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
-
- /* only a single instance is supported */
- break;
- }
-
- debug("< %s()\n", __func__);
- return 0;
-}
-
-struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
-{
- struct tegra_xusb_phy *phy = NULL;
-
- switch (type) {
- case TEGRA_XUSB_PADCTL_PCIE:
- phy = &padctl->phys[0];
- phy->padctl = padctl;
- break;
- }
-
- return phy;
-}
-
-int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->prepare)
- return phy->ops->prepare(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->enable)
- return phy->ops->enable(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->disable)
- return phy->ops->disable(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
-
-int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
-{
- if (phy && phy->ops && phy->ops->unprepare)
- return phy->ops->unprepare(phy);
-
- return phy ? -ENOSYS : -EINVAL;
-}
+static const struct tegra_xusb_padctl_soc tegra210_socdata = {
+ .lanes = tegra210_lanes,
+ .num_lanes = ARRAY_SIZE(tegra210_lanes),
+ .functions = tegra210_functions,
+ .num_functions = ARRAY_SIZE(tegra210_functions),
+ .phys = tegra210_phys,
+ .num_phys = ARRAY_SIZE(tegra210_phys),
+};
void tegra_xusb_padctl_init(const void *fdt)
{
@@ -482,13 +430,7 @@ void tegra_xusb_padctl_init(const void *fdt)
count = fdtdec_find_aliases_for_id(fdt, "padctl",
COMPAT_NVIDIA_TEGRA210_XUSB_PADCTL,
nodes, ARRAY_SIZE(nodes));
- if (process_nodes(fdt, nodes, count))
- return;
-
- count = fdtdec_find_aliases_for_id(fdt, "padctl",
- COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
- nodes, ARRAY_SIZE(nodes));
- if (process_nodes(fdt, nodes, count))
+ if (tegra_xusb_process_nodes(fdt, nodes, count, &tegra210_socdata))
return;
debug("< %s()\n", __func__);
diff --git a/arch/arm/mach-tegra/xusb-padctl-common.c b/arch/arm/mach-tegra/xusb-padctl-common.c
new file mode 100644
index 0000000000..18ad7bfbdc
--- /dev/null
+++ b/arch/arm/mach-tegra/xusb-padctl-common.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#define pr_fmt(fmt) "tegra-xusb-padctl: " fmt
+
+#include <common.h>
+#include <errno.h>
+
+#include "xusb-padctl-common.h"
+
+#include <asm/arch/clock.h>
+
+int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
+{
+ if (phy && phy->ops && phy->ops->prepare)
+ return phy->ops->prepare(phy);
+
+ return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
+{
+ if (phy && phy->ops && phy->ops->enable)
+ return phy->ops->enable(phy);
+
+ return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
+{
+ if (phy && phy->ops && phy->ops->disable)
+ return phy->ops->disable(phy);
+
+ return phy ? -ENOSYS : -EINVAL;
+}
+
+int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
+{
+ if (phy && phy->ops && phy->ops->unprepare)
+ return phy->ops->unprepare(phy);
+
+ return phy ? -ENOSYS : -EINVAL;
+}
+
+struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
+{
+ struct tegra_xusb_phy *phy;
+ int i;
+
+ for (i = 0; i < padctl.socdata->num_phys; i++) {
+ phy = &padctl.socdata->phys[i];
+ if (phy->type != type)
+ continue;
+ return phy;
+ }
+
+ return NULL;
+}
+
+static const struct tegra_xusb_padctl_lane *
+tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < padctl->socdata->num_lanes; i++)
+ if (strcmp(name, padctl->socdata->lanes[i].name) == 0)
+ return &padctl->socdata->lanes[i];
+
+ return NULL;
+}
+
+static int
+tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl,
+ struct tegra_xusb_padctl_group *group,
+ const void *fdt, int node)
+{
+ unsigned int i;
+ int len, err;
+
+ group->name = fdt_get_name(fdt, node, &len);
+
+ len = fdt_count_strings(fdt, node, "nvidia,lanes");
+ if (len < 0) {
+ error("failed to parse \"nvidia,lanes\" property");
+ return -EINVAL;
+ }
+
+ group->num_pins = len;
+
+ for (i = 0; i < group->num_pins; i++) {
+ err = fdt_get_string_index(fdt, node, "nvidia,lanes", i,
+ &group->pins[i]);
+ if (err < 0) {
+ error("failed to read string from \"nvidia,lanes\" property");
+ return -EINVAL;
+ }
+ }
+
+ group->num_pins = len;
+
+ err = fdt_get_string(fdt, node, "nvidia,function", &group->func);
+ if (err < 0) {
+ error("failed to parse \"nvidia,func\" property");
+ return -EINVAL;
+ }
+
+ group->iddq = fdtdec_get_int(fdt, node, "nvidia,iddq", -1);
+
+ return 0;
+}
+
+static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl,
+ const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < padctl->socdata->num_functions; i++)
+ if (strcmp(name, padctl->socdata->functions[i]) == 0)
+ return i;
+
+ return -ENOENT;
+}
+
+static int
+tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl,
+ const struct tegra_xusb_padctl_lane *lane,
+ const char *name)
+{
+ unsigned int i;
+ int func;
+
+ func = tegra_xusb_padctl_find_function(padctl, name);
+ if (func < 0)
+ return func;
+
+ for (i = 0; i < lane->num_funcs; i++)
+ if (lane->funcs[i] == func)
+ return i;
+
+ return -ENOENT;
+}
+
+static int
+tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl,
+ const struct tegra_xusb_padctl_group *group)
+{
+ unsigned int i;
+
+ for (i = 0; i < group->num_pins; i++) {
+ const struct tegra_xusb_padctl_lane *lane;
+ unsigned int func;
+ u32 value;
+
+ lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]);
+ if (!lane) {
+ error("no lane for pin %s", group->pins[i]);
+ continue;
+ }
+
+ func = tegra_xusb_padctl_lane_find_function(padctl, lane,
+ group->func);
+ if (func < 0) {
+ error("function %s invalid for lane %s: %d",
+ group->func, lane->name, func);
+ continue;
+ }
+
+ value = padctl_readl(padctl, lane->offset);
+
+ /* set pin function */
+ value &= ~(lane->mask << lane->shift);
+ value |= func << lane->shift;
+
+ /*
+ * Set IDDQ if supported on the lane and specified in the
+ * configuration.
+ */
+ if (lane->iddq > 0 && group->iddq >= 0) {
+ if (group->iddq != 0)
+ value &= ~(1 << lane->iddq);
+ else
+ value |= 1 << lane->iddq;
+ }
+
+ padctl_writel(padctl, value, lane->offset);
+ }
+
+ return 0;
+}
+
+static int
+tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl,
+ struct tegra_xusb_padctl_config *config)
+{
+ unsigned int i;
+
+ for (i = 0; i < config->num_groups; i++) {
+ const struct tegra_xusb_padctl_group *group;
+ int err;
+
+ group = &config->groups[i];
+
+ err = tegra_xusb_padctl_group_apply(padctl, group);
+ if (err < 0) {
+ error("failed to apply group %s: %d",
+ group->name, err);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+static int
+tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl,
+ struct tegra_xusb_padctl_config *config,
+ const void *fdt, int node)
+{
+ int subnode;
+
+ config->name = fdt_get_name(fdt, node, NULL);
+
+ fdt_for_each_subnode(fdt, subnode, node) {
+ struct tegra_xusb_padctl_group *group;
+ int err;
+
+ group = &config->groups[config->num_groups];
+
+ err = tegra_xusb_padctl_group_parse_dt(padctl, group, fdt,
+ subnode);
+ if (err < 0) {
+ error("failed to parse group %s", group->name);
+ return err;
+ }
+
+ config->num_groups++;
+ }
+
+ return 0;
+}
+
+static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
+ const void *fdt, int node)
+{
+ int subnode, err;
+
+ err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs);
+ if (err < 0) {
+ error("registers not found");
+ return err;
+ }
+
+ fdt_for_each_subnode(fdt, subnode, node) {
+ struct tegra_xusb_padctl_config *config = &padctl->config;
+
+ err = tegra_xusb_padctl_config_parse_dt(padctl, config, fdt,
+ subnode);
+ if (err < 0) {
+ error("failed to parse entry %s: %d",
+ config->name, err);
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+struct tegra_xusb_padctl padctl;
+
+int tegra_xusb_process_nodes(const void *fdt, int nodes[], unsigned int count,
+ const struct tegra_xusb_padctl_soc *socdata)
+{
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < count; i++) {
+ if (!fdtdec_get_is_enabled(fdt, nodes[i]))
+ continue;
+
+ padctl.socdata = socdata;
+
+ err = tegra_xusb_padctl_parse_dt(&padctl, fdt, nodes[i]);
+ if (err < 0) {
+ error("failed to parse DT: %d", err);
+ continue;
+ }
+
+ /* deassert XUSB padctl reset */
+ reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
+
+ err = tegra_xusb_padctl_config_apply(&padctl, &padctl.config);
+ if (err < 0) {
+ error("failed to apply pinmux: %d", err);
+ continue;
+ }
+
+ /* only a single instance is supported */
+ break;
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/xusb-padctl-common.h b/arch/arm/mach-tegra/xusb-padctl-common.h
new file mode 100644
index 0000000000..f44790a650
--- /dev/null
+++ b/arch/arm/mach-tegra/xusb-padctl-common.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _TEGRA_XUSB_PADCTL_COMMON_H_
+#define _TEGRA_XUSB_PADCTL_COMMON_H_
+
+#include <common.h>
+#include <fdtdec.h>
+
+#include <asm/io.h>
+#include <asm/arch-tegra/xusb-padctl.h>
+
+struct tegra_xusb_padctl_lane {
+ const char *name;
+
+ unsigned int offset;
+ unsigned int shift;
+ unsigned int mask;
+ unsigned int iddq;
+
+ const unsigned int *funcs;
+ unsigned int num_funcs;
+};
+
+struct tegra_xusb_phy_ops {
+ int (*prepare)(struct tegra_xusb_phy *phy);
+ int (*enable)(struct tegra_xusb_phy *phy);
+ int (*disable)(struct tegra_xusb_phy *phy);
+ int (*unprepare)(struct tegra_xusb_phy *phy);
+};
+
+struct tegra_xusb_phy {
+ unsigned int type;
+ const struct tegra_xusb_phy_ops *ops;
+ struct tegra_xusb_padctl *padctl;
+};
+
+struct tegra_xusb_padctl_pin {
+ const struct tegra_xusb_padctl_lane *lane;
+
+ unsigned int func;
+ int iddq;
+};
+
+#define MAX_GROUPS 5
+#define MAX_PINS 7
+
+struct tegra_xusb_padctl_group {
+ const char *name;
+
+ const char *pins[MAX_PINS];
+ unsigned int num_pins;
+
+ const char *func;
+ int iddq;
+};
+
+struct tegra_xusb_padctl_soc {
+ const struct tegra_xusb_padctl_lane *lanes;
+ unsigned int num_lanes;
+ const char *const *functions;
+ unsigned int num_functions;
+ struct tegra_xusb_phy *phys;
+ unsigned int num_phys;
+};
+
+struct tegra_xusb_padctl_config {
+ const char *name;
+
+ struct tegra_xusb_padctl_group groups[MAX_GROUPS];
+ unsigned int num_groups;
+};
+
+struct tegra_xusb_padctl {
+ const struct tegra_xusb_padctl_soc *socdata;
+ struct tegra_xusb_padctl_config config;
+ struct fdt_resource regs;
+ unsigned int enable;
+
+};
+extern struct tegra_xusb_padctl padctl;
+
+static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
+ unsigned long offset)
+{
+ return readl(padctl->regs.start + offset);
+}
+
+static inline void padctl_writel(struct tegra_xusb_padctl *padctl,
+ u32 value, unsigned long offset)
+{
+ writel(value, padctl->regs.start + offset);
+}
+
+int tegra_xusb_process_nodes(const void *fdt, int nodes[], unsigned int count,
+ const struct tegra_xusb_padctl_soc *socdata);
+
+#endif
diff --git a/arch/arm/mach-tegra/xusb-padctl.c b/arch/arm/mach-tegra/xusb-padctl-dummy.c
index 65f8d2ea96..65f8d2ea96 100644
--- a/arch/arm/mach-tegra/xusb-padctl.c
+++ b/arch/arm/mach-tegra/xusb-padctl-dummy.c