mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-25 12:33:41 +00:00
1e94b46f73
This old patch was marked as deferred. Bring it back to life, to continue towards the removal of common.h Move this out of the common header and include it only where needed. Signed-off-by: Simon Glass <sjg@chromium.org>
354 lines
9.8 KiB
C
354 lines
9.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "tegra-xusb-padctl: " fmt
|
|
|
|
#include <common.h>
|
|
#include <errno.h>
|
|
#include <log.h>
|
|
#include <dm/of_access.h>
|
|
#include <dm/ofnode.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/printk.h>
|
|
#include <asm/global_data.h>
|
|
|
|
#include "../xusb-padctl-common.h"
|
|
|
|
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
|
|
|
|
#define XUSB_PADCTL_ELPG_PROGRAM 0x01c
|
|
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
|
|
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
|
|
#define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
|
|
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12)
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
|
|
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
|
|
#define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
|
|
|
|
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
|
|
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
|
|
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
|
|
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
|
|
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1)
|
|
#define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
|
|
|
|
#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
|
|
#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
|
|
#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
|
|
|
|
enum tegra124_function {
|
|
TEGRA124_FUNC_SNPS,
|
|
TEGRA124_FUNC_XUSB,
|
|
TEGRA124_FUNC_UART,
|
|
TEGRA124_FUNC_PCIE,
|
|
TEGRA124_FUNC_USB3,
|
|
TEGRA124_FUNC_SATA,
|
|
TEGRA124_FUNC_RSVD,
|
|
};
|
|
|
|
static const char *const tegra124_functions[] = {
|
|
"snps",
|
|
"xusb",
|
|
"uart",
|
|
"pcie",
|
|
"usb3",
|
|
"sata",
|
|
"rsvd",
|
|
};
|
|
|
|
static const unsigned int tegra124_otg_functions[] = {
|
|
TEGRA124_FUNC_SNPS,
|
|
TEGRA124_FUNC_XUSB,
|
|
TEGRA124_FUNC_UART,
|
|
TEGRA124_FUNC_RSVD,
|
|
};
|
|
|
|
static const unsigned int tegra124_usb_functions[] = {
|
|
TEGRA124_FUNC_SNPS,
|
|
TEGRA124_FUNC_XUSB,
|
|
};
|
|
|
|
static const unsigned int tegra124_pci_functions[] = {
|
|
TEGRA124_FUNC_PCIE,
|
|
TEGRA124_FUNC_USB3,
|
|
TEGRA124_FUNC_SATA,
|
|
TEGRA124_FUNC_RSVD,
|
|
};
|
|
|
|
#define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs) \
|
|
{ \
|
|
.name = _name, \
|
|
.offset = _offset, \
|
|
.shift = _shift, \
|
|
.mask = _mask, \
|
|
.iddq = _iddq, \
|
|
.num_funcs = ARRAY_SIZE(tegra124_##_funcs##_functions), \
|
|
.funcs = tegra124_##_funcs##_functions, \
|
|
}
|
|
|
|
static const struct tegra_xusb_padctl_lane tegra124_lanes[] = {
|
|
TEGRA124_LANE("otg-0", 0x004, 0, 0x3, 0, otg),
|
|
TEGRA124_LANE("otg-1", 0x004, 2, 0x3, 0, otg),
|
|
TEGRA124_LANE("otg-2", 0x004, 4, 0x3, 0, otg),
|
|
TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb),
|
|
TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb),
|
|
TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb),
|
|
TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci),
|
|
TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci),
|
|
TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci),
|
|
TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci),
|
|
TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci),
|
|
TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci),
|
|
};
|
|
|
|
static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
|
|
{
|
|
u32 value;
|
|
|
|
if (padctl->enable++ > 0)
|
|
return 0;
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
|
|
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
|
|
|
|
udelay(100);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
|
|
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
|
|
|
|
udelay(100);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
|
|
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
|
|
{
|
|
u32 value;
|
|
|
|
if (padctl->enable == 0) {
|
|
pr_err("unbalanced enable/disable");
|
|
return 0;
|
|
}
|
|
|
|
if (--padctl->enable > 0)
|
|
return 0;
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
|
|
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
|
|
|
|
udelay(100);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
|
|
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
|
|
|
|
udelay(100);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
|
|
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int phy_prepare(struct tegra_xusb_phy *phy)
|
|
{
|
|
return tegra_xusb_padctl_enable(phy->padctl);
|
|
}
|
|
|
|
static int phy_unprepare(struct tegra_xusb_phy *phy)
|
|
{
|
|
return tegra_xusb_padctl_disable(phy->padctl);
|
|
}
|
|
|
|
static int pcie_phy_enable(struct tegra_xusb_phy *phy)
|
|
{
|
|
struct tegra_xusb_padctl *padctl = phy->padctl;
|
|
int err = -ETIMEDOUT;
|
|
unsigned long start;
|
|
u32 value;
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
|
|
value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
|
|
value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN |
|
|
XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN |
|
|
XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
|
|
value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
|
|
|
|
start = get_timer(0);
|
|
|
|
while (get_timer(start) < 50) {
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
|
|
if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) {
|
|
err = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int pcie_phy_disable(struct tegra_xusb_phy *phy)
|
|
{
|
|
struct tegra_xusb_padctl *padctl = phy->padctl;
|
|
u32 value;
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
|
|
value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sata_phy_enable(struct tegra_xusb_phy *phy)
|
|
{
|
|
struct tegra_xusb_padctl *padctl = phy->padctl;
|
|
int err = -ETIMEDOUT;
|
|
unsigned long start;
|
|
u32 value;
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
|
|
value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
|
|
value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
|
|
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
|
|
start = get_timer(0);
|
|
|
|
while (get_timer(start) < 50) {
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) {
|
|
err = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int sata_phy_disable(struct tegra_xusb_phy *phy)
|
|
{
|
|
struct tegra_xusb_padctl *padctl = phy->padctl;
|
|
u32 value;
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
|
|
value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
|
|
|
|
value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
|
|
value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
|
|
value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
|
|
padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct tegra_xusb_phy_ops pcie_phy_ops = {
|
|
.prepare = phy_prepare,
|
|
.enable = pcie_phy_enable,
|
|
.disable = pcie_phy_disable,
|
|
.unprepare = phy_unprepare,
|
|
};
|
|
|
|
static const struct tegra_xusb_phy_ops sata_phy_ops = {
|
|
.prepare = phy_prepare,
|
|
.enable = sata_phy_enable,
|
|
.disable = sata_phy_disable,
|
|
.unprepare = phy_unprepare,
|
|
};
|
|
|
|
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_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(void)
|
|
{
|
|
ofnode nodes[1];
|
|
int count = 0;
|
|
int ret;
|
|
|
|
debug("%s: start\n", __func__);
|
|
if (of_live_active()) {
|
|
struct device_node *np = of_find_compatible_node(NULL, NULL,
|
|
"nvidia,tegra124-xusb-padctl");
|
|
|
|
debug("np=%p\n", np);
|
|
if (np) {
|
|
nodes[0] = np_to_ofnode(np);
|
|
count = 1;
|
|
}
|
|
} else {
|
|
int node_offsets[1];
|
|
int i;
|
|
|
|
count = fdtdec_find_aliases_for_id(gd->fdt_blob, "padctl",
|
|
COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,
|
|
node_offsets, ARRAY_SIZE(node_offsets));
|
|
for (i = 0; i < count; i++)
|
|
nodes[i] = offset_to_ofnode(node_offsets[i]);
|
|
}
|
|
|
|
ret = tegra_xusb_process_nodes(nodes, count, &tegra124_socdata);
|
|
debug("%s: done, ret=%d\n", __func__, ret);
|
|
}
|