Merge branch 'master' of git://git.denx.de/u-boot-tegra

This commit is contained in:
Tom Rini 2015-11-12 15:59:35 -05:00
commit bc80109b11
30 changed files with 1355 additions and 671 deletions

View file

@ -21,6 +21,56 @@
reg = <0x0 0x80000000 0x0 0xc0000000>;
};
pcie-controller@0,01003000 {
status = "okay";
pci@1,0 {
status = "okay";
};
pci@2,0 {
status = "okay";
};
};
padctl@0,7009f000 {
pinctrl-0 = <&padctl_default>;
pinctrl-names = "default";
padctl_default: pinmux {
xusb {
nvidia,lanes = "otg-1", "otg-2";
nvidia,function = "xusb";
nvidia,iddq = <0>;
};
usb3 {
nvidia,lanes = "pcie-5", "pcie-6";
nvidia,function = "usb3";
nvidia,iddq = <0>;
};
pcie-x1 {
nvidia,lanes = "pcie-0";
nvidia,function = "pcie-x1";
nvidia,iddq = <0>;
};
pcie-x4 {
nvidia,lanes = "pcie-1", "pcie-2",
"pcie-3", "pcie-4";
nvidia,function = "pcie-x4";
nvidia,iddq = <0>;
};
sata {
nvidia,lanes = "sata-0";
nvidia,function = "sata";
nvidia,iddq = <0>;
};
};
};
sdhci@0,700b0000 {
status = "okay";
cd-gpios = <&gpio TEGRA_GPIO(Z, 1) GPIO_ACTIVE_LOW>;

View file

@ -12,6 +12,72 @@
#address-cells = <2>;
#size-cells = <2>;
pcie-controller@0,01003000 {
compatible = "nvidia,tegra210-pcie";
device_type = "pci";
reg = <0x0 0x01003000 0x0 0x00000800 /* PADS registers */
0x0 0x01003800 0x0 0x00000800 /* AFI registers */
0x0 0x02000000 0x0 0x10000000>; /* configuration space */
reg-names = "pads", "afi", "cs";
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
<GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */
interrupt-names = "intr", "msi";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
bus-range = <0x00 0xff>;
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x82000000 0 0x01000000 0x0 0x01000000 0 0x00001000 /* port 0 configuration space */
0x82000000 0 0x01001000 0x0 0x01001000 0 0x00001000 /* port 1 configuration space */
0x81000000 0 0x0 0x0 0x12000000 0 0x00010000 /* downstream I/O (64 KiB) */
0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000 /* non-prefetchable memory (208 MiB) */
0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */
clocks = <&tegra_car TEGRA210_CLK_PCIE>,
<&tegra_car TEGRA210_CLK_AFI>,
<&tegra_car TEGRA210_CLK_PLL_E>,
<&tegra_car TEGRA210_CLK_CML0>;
clock-names = "pex", "afi", "pll_e", "cml";
resets = <&tegra_car 70>,
<&tegra_car 72>,
<&tegra_car 74>;
reset-names = "pex", "afi", "pcie_x";
status = "disabled";
phys = <&padctl TEGRA_XUSB_PADCTL_PCIE>;
phy-names = "pcie";
pci@1,0 {
device_type = "pci";
assigned-addresses = <0x82000800 0 0x01000000 0 0x1000>;
reg = <0x000800 0 0 0 0>;
status = "disabled";
#address-cells = <3>;
#size-cells = <2>;
ranges;
nvidia,num-lanes = <4>;
};
pci@2,0 {
device_type = "pci";
assigned-addresses = <0x82001000 0 0x01001000 0 0x1000>;
reg = <0x001000 0 0 0 0>;
status = "disabled";
#address-cells = <3>;
#size-cells = <2>;
ranges;
nvidia,num-lanes = <1>;
};
};
gic: interrupt-controller@0,50041000 {
compatible = "arm,gic-400";
#interrupt-cells = <3>;

View file

@ -10,29 +10,23 @@
#if defined(CONFIG_TEGRA_GPU)
void config_gpu(void);
bool gpu_configured(void);
void tegra_gpu_config(void);
#else /* CONFIG_TEGRA_GPU */
static inline void config_gpu(void)
static inline void tegra_gpu_config(void)
{
}
static inline bool gpu_configured(void)
{
return false;
}
#endif /* CONFIG_TEGRA_GPU */
#if defined(CONFIG_OF_LIBFDT)
int gpu_enable_node(void *blob, const char *gpupath);
int tegra_gpu_enable_node(void *blob, const char *gpupath);
#else /* CONFIG_OF_LIBFDT */
static inline int gpu_enable_node(void *blob, const char *gpupath)
static inline int tegra_gpu_enable_node(void *blob, const char *gpupath)
{
return 0;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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"

View file

@ -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

View file

@ -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);
/* 4. Wait for LOCK */
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");
/* 5. Enable SSA */
value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
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_SSCINCINTR(0x3f);
value &= ~PLLE_SS_CNTL_SSCINC(0xff);
value &= ~PLLE_SS_CNTL_SSCMAX(0x1ff);
value |= PLLE_SS_CNTL_SSCINCINTR(0x20);
value |= PLLE_SS_CNTL_SSCINC(0x01);
value |= PLLE_SS_CNTL_SSCMAX(0x25);
writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
value &= ~PLLE_SS_CNTL_SSCBYP;
value &= ~PLLE_SS_CNTL_BYPASS_SS;
value &= ~PLLE_SS_CNTL_SSCBYP;
writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
/* 6. Wait 300 ns */
udelay(1);
value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
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;
}

View file

@ -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;
unsigned int enable;
struct tegra_xusb_phy phys[2];
static const unsigned int tegra210_otg_functions[] = {
TEGRA210_FUNC_SNPS,
TEGRA210_FUNC_XUSB,
TEGRA210_FUNC_UART,
TEGRA210_FUNC_RSVD,
};
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;
}
static const unsigned int tegra210_usb_functions[] = {
TEGRA210_FUNC_SNPS,
TEGRA210_FUNC_XUSB,
};
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 unsigned int tegra210_pci_functions[] = {
TEGRA210_FUNC_PCIE_X1,
TEGRA210_FUNC_USB3,
TEGRA210_FUNC_SATA,
TEGRA210_FUNC_PCIE_X4,
};
#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 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__);

View file

@ -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;
}

View file

@ -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

View file

@ -11,7 +11,6 @@
#include <asm/arch/gpio.h>
#include <asm/arch/pinmux.h>
#include <asm/arch-tegra/gpu.h>
#include "pinmux-config-jetson-tk1.h"
@ -80,10 +79,3 @@ int board_eth_init(bd_t *bis)
return pci_eth_init(bis);
}
#endif /* PCI */
int ft_board_setup(void *blob, bd_t *bd)
{
gpu_enable_node(blob, "/gpu@0,57000000");
return 0;
}

View file

@ -6,6 +6,7 @@
*/
#include <common.h>
#include <netdev.h>
#include <i2c.h>
#include <asm/arch/gpio.h>
#include <asm/arch/pinmux.h>
@ -49,3 +50,32 @@ void pinmux_init(void)
pinmux_config_drvgrp_table(p2371_2180_drvgrps,
ARRAY_SIZE(p2371_2180_drvgrps));
}
#ifdef CONFIG_PCI_TEGRA
int tegra_pcie_board_init(void)
{
struct udevice *dev;
uchar val;
int ret;
/* Turn on MAX77620 LDO1 to 1.05V for PEX power */
debug("%s: Set LDO1 for PEX power to 1.05V\n", __func__);
ret = i2c_get_chip_for_busnum(0, MAX77620_I2C_ADDR_7BIT, 1, &dev);
if (ret) {
printf("%s: Cannot find MAX77620 I2C chip\n", __func__);
return -1;
}
/* 0xCA for 1.05v, enabled: bit7:6 = 11 = enable, bit5:0 = voltage */
val = 0xCA;
ret = dm_i2c_write(dev, MAX77620_CNFG1_L1_REG, &val, 1);
if (ret)
printf("i2c_write 0 0x3c 0x25 failed: %d\n", ret);
return 0;
}
int board_eth_init(bd_t *bis)
{
return pci_eth_init(bis);
}
#endif /* PCI */

View file

@ -11,7 +11,6 @@
#include <asm/arch/pinmux.h>
#include <asm/gpio.h>
#include "max77620_init.h"
#include <asm/arch-tegra/gpu.h>
#include "pinmux-config-p2571.h"
void pin_mux_mmc(void)
@ -62,9 +61,3 @@ void start_cpu_fan(void)
gpio_request(GPIO_PE4, "FAN_VDD");
gpio_direction_output(GPIO_PE4, 1);
}
int ft_board_setup(void *blob, bd_t *bd)
{
gpu_enable_node(blob, "/gpu@0,57000000");
return 0;
}

View file

@ -8,7 +8,6 @@
#include <common.h>
#include <asm/arch/gpio.h>
#include <asm/arch/pinmux.h>
#include <asm/arch-tegra/gpu.h>
#include "pinmux-config-venice2.h"
/*
@ -28,10 +27,3 @@ void pinmux_init(void)
pinmux_config_drvgrp_table(venice2_drvgrps,
ARRAY_SIZE(venice2_drvgrps));
}
int ft_board_setup(void *blob, bd_t *bd)
{
gpu_enable_node(blob, "/gpu@0,57000000");
return 0;
}

View file

@ -166,6 +166,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define RP_VEND_XP 0x00000F00
#define RP_VEND_XP_DL_UP (1 << 30)
#define RP_VEND_CTL2 0x00000FA8
#define RP_VEND_CTL2_PCA_ENABLE (1 << 7)
#define RP_PRIV_MISC 0x00000FE0
#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
@ -194,6 +197,7 @@ struct tegra_pcie_soc {
bool has_pex_bias_ctrl;
bool has_cml_clk;
bool has_gen2;
bool force_pca_enable;
};
struct tegra_pcie {
@ -383,6 +387,7 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
break;
case COMPAT_NVIDIA_TEGRA124_PCIE:
case COMPAT_NVIDIA_TEGRA210_PCIE:
switch (lanes) {
case 0x0000104:
debug("4x1, 1x1 configuration\n");
@ -406,9 +411,34 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes,
static int tegra_pcie_parse_dt_ranges(const void *fdt, int node,
struct tegra_pcie *pcie)
{
int parent, na_parent, na_pcie, ns_pcie;
const u32 *ptr, *end;
int len;
parent = fdt_parent_offset(fdt, node);
if (parent < 0) {
error("Can't find PCI parent node\n");
return -FDT_ERR_NOTFOUND;
}
na_parent = fdt_address_cells(fdt, parent);
if (na_parent < 1) {
error("bad #address-cells for PCIE parent\n");
return -FDT_ERR_NOTFOUND;
}
na_pcie = fdt_address_cells(fdt, node);
if (na_pcie < 1) {
error("bad #address-cells for PCIE\n");
return -FDT_ERR_NOTFOUND;
}
ns_pcie = fdt_size_cells(fdt, node);
if (ns_pcie < 1) {
error("bad #size-cells for PCIE\n");
return -FDT_ERR_NOTFOUND;
}
ptr = fdt_getprop(fdt, node, "ranges", &len);
if (!ptr) {
error("missing \"ranges\" property");
@ -437,11 +467,13 @@ static int tegra_pcie_parse_dt_ranges(const void *fdt, int node,
}
if (res) {
res->start = fdt32_to_cpu(ptr[3]);
res->end = res->start + fdt32_to_cpu(ptr[5]);
int start_low = na_pcie + (na_parent - 1);
int size_low = na_pcie + na_parent + (ns_pcie - 1);
res->start = fdt32_to_cpu(ptr[start_low]);
res->end = res->start + fdt32_to_cpu(ptr[size_low]);
}
ptr += 3 + 1 + 2;
ptr += na_pcie + na_parent + ns_pcie;
}
debug("PCI regions:\n");
@ -587,8 +619,6 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
return err;
}
tegra_pcie_board_init();
err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
PERIPH_ID_PCIE);
if (err < 0) {
@ -860,6 +890,7 @@ static void tegra_pcie_port_reset(struct tegra_pcie_port *port)
static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc *soc = port->pcie->soc;
unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
unsigned long value;
@ -875,6 +906,12 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
afi_writel(port->pcie, value, ctrl);
tegra_pcie_port_reset(port);
if (soc->force_pca_enable) {
value = rp_readl(port, RP_VEND_CTL2);
value |= RP_VEND_CTL2_PCA_ENABLE;
rp_writel(port, value, RP_VEND_CTL2);
}
}
static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
@ -972,6 +1009,7 @@ static const struct tegra_pcie_soc tegra20_pcie_soc = {
.has_pex_bias_ctrl = false,
.has_cml_clk = false,
.has_gen2 = false,
.force_pca_enable = false,
};
static const struct tegra_pcie_soc tegra30_pcie_soc = {
@ -982,6 +1020,7 @@ static const struct tegra_pcie_soc tegra30_pcie_soc = {
.has_pex_bias_ctrl = true,
.has_cml_clk = true,
.has_gen2 = false,
.force_pca_enable = false,
};
static const struct tegra_pcie_soc tegra124_pcie_soc = {
@ -992,11 +1031,31 @@ static const struct tegra_pcie_soc tegra124_pcie_soc = {
.has_pex_bias_ctrl = true,
.has_cml_clk = true,
.has_gen2 = true,
.force_pca_enable = false,
};
static const struct tegra_pcie_soc tegra210_pcie_soc = {
.num_ports = 2,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.has_pex_clkreq_en = true,
.has_pex_bias_ctrl = true,
.has_cml_clk = true,
.has_gen2 = true,
.force_pca_enable = true,
};
static int process_nodes(const void *fdt, int nodes[], unsigned int count)
{
unsigned int i;
uint64_t dram_end;
uint32_t pci_dram_size;
/* Clip PCI-accessible DRAM to 32-bits */
dram_end = ((uint64_t)NV_PA_SDRAM_BASE) + gd->ram_size;
if (dram_end > 0x100000000)
dram_end = 0x100000000;
pci_dram_size = dram_end - NV_PA_SDRAM_BASE;
for (i = 0; i < count; i++) {
const struct tegra_pcie_soc *soc;
@ -1021,6 +1080,10 @@ static int process_nodes(const void *fdt, int nodes[], unsigned int count)
soc = &tegra124_pcie_soc;
break;
case COMPAT_NVIDIA_TEGRA210_PCIE:
soc = &tegra210_pcie_soc;
break;
default:
error("unsupported compatible: %s",
fdtdec_get_compatible(id));
@ -1069,7 +1132,7 @@ static int process_nodes(const void *fdt, int nodes[], unsigned int count)
pcie->hose.last_busno = 0;
pci_set_region(&pcie->hose.regions[0], NV_PA_SDRAM_BASE,
NV_PA_SDRAM_BASE, gd->ram_size,
NV_PA_SDRAM_BASE, pci_dram_size,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
pci_set_region(&pcie->hose.regions[1], pcie->io.start,
@ -1115,6 +1178,14 @@ void pci_init_board(void)
const void *fdt = gd->fdt_blob;
int count, nodes[1];
tegra_pcie_board_init();
count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
COMPAT_NVIDIA_TEGRA210_PCIE,
nodes, ARRAY_SIZE(nodes));
if (process_nodes(fdt, nodes, count))
return;
count = fdtdec_find_aliases_for_id(fdt, "pcie-controller",
COMPAT_NVIDIA_TEGRA124_PCIE,
nodes, ARRAY_SIZE(nodes));

View file

@ -123,6 +123,13 @@ config TEGRA20_SLINK
be used to access the SPI NOR flash on platforms embedding this
nVidia Tegra20/Tegra30 IP cores.
config TEGRA210_QSPI
bool "nVidia Tegra210 QSPI driver"
help
Enable the Tegra Quad-SPI (QSPI) driver for T210. This driver
be used to access SPI chips on platforms embedding this
NVIDIA Tegra210 IP core.
config XILINX_SPI
bool "Xilinx SPI driver"
help

View file

@ -46,6 +46,7 @@ obj-$(CONFIG_SH_QSPI) += sh_qspi.o
obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o
obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o
obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o
obj-$(CONFIG_TEGRA210_QSPI) += tegra210_qspi.o
obj-$(CONFIG_TI_QSPI) += ti_qspi.o
obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
obj-$(CONFIG_ZYNQ_SPI) += zynq_spi.o

417
drivers/spi/tegra210_qspi.c Normal file
View file

@ -0,0 +1,417 @@
/*
* NVIDIA Tegra210 QSPI controller driver
*
* (C) Copyright 2015 NVIDIA Corporation <www.nvidia.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch-tegra/clk_rst.h>
#include <spi.h>
#include <fdtdec.h>
#include "tegra_spi.h"
DECLARE_GLOBAL_DATA_PTR;
/* COMMAND1 */
#define QSPI_CMD1_GO BIT(31)
#define QSPI_CMD1_M_S BIT(30)
#define QSPI_CMD1_MODE_MASK GENMASK(1,0)
#define QSPI_CMD1_MODE_SHIFT 28
#define QSPI_CMD1_CS_SEL_MASK GENMASK(1,0)
#define QSPI_CMD1_CS_SEL_SHIFT 26
#define QSPI_CMD1_CS_POL_INACTIVE0 BIT(22)
#define QSPI_CMD1_CS_SW_HW BIT(21)
#define QSPI_CMD1_CS_SW_VAL BIT(20)
#define QSPI_CMD1_IDLE_SDA_MASK GENMASK(1,0)
#define QSPI_CMD1_IDLE_SDA_SHIFT 18
#define QSPI_CMD1_BIDIR BIT(17)
#define QSPI_CMD1_LSBI_FE BIT(16)
#define QSPI_CMD1_LSBY_FE BIT(15)
#define QSPI_CMD1_BOTH_EN_BIT BIT(14)
#define QSPI_CMD1_BOTH_EN_BYTE BIT(13)
#define QSPI_CMD1_RX_EN BIT(12)
#define QSPI_CMD1_TX_EN BIT(11)
#define QSPI_CMD1_PACKED BIT(5)
#define QSPI_CMD1_BITLEN_MASK GENMASK(4,0)
#define QSPI_CMD1_BITLEN_SHIFT 0
/* COMMAND2 */
#define QSPI_CMD2_TX_CLK_TAP_DELAY BIT(6)
#define QSPI_CMD2_TX_CLK_TAP_DELAY_MASK GENMASK(11,6)
#define QSPI_CMD2_RX_CLK_TAP_DELAY BIT(0)
#define QSPI_CMD2_RX_CLK_TAP_DELAY_MASK GENMASK(5,0)
/* TRANSFER STATUS */
#define QSPI_XFER_STS_RDY BIT(30)
/* FIFO STATUS */
#define QSPI_FIFO_STS_CS_INACTIVE BIT(31)
#define QSPI_FIFO_STS_FRAME_END BIT(30)
#define QSPI_FIFO_STS_RX_FIFO_FLUSH BIT(15)
#define QSPI_FIFO_STS_TX_FIFO_FLUSH BIT(14)
#define QSPI_FIFO_STS_ERR BIT(8)
#define QSPI_FIFO_STS_TX_FIFO_OVF BIT(7)
#define QSPI_FIFO_STS_TX_FIFO_UNR BIT(6)
#define QSPI_FIFO_STS_RX_FIFO_OVF BIT(5)
#define QSPI_FIFO_STS_RX_FIFO_UNR BIT(4)
#define QSPI_FIFO_STS_TX_FIFO_FULL BIT(3)
#define QSPI_FIFO_STS_TX_FIFO_EMPTY BIT(2)
#define QSPI_FIFO_STS_RX_FIFO_FULL BIT(1)
#define QSPI_FIFO_STS_RX_FIFO_EMPTY BIT(0)
#define QSPI_TIMEOUT 1000
struct qspi_regs {
u32 command1; /* 000:QSPI_COMMAND1 register */
u32 command2; /* 004:QSPI_COMMAND2 register */
u32 timing1; /* 008:QSPI_CS_TIM1 register */
u32 timing2; /* 00c:QSPI_CS_TIM2 register */
u32 xfer_status;/* 010:QSPI_TRANS_STATUS register */
u32 fifo_status;/* 014:QSPI_FIFO_STATUS register */
u32 tx_data; /* 018:QSPI_TX_DATA register */
u32 rx_data; /* 01c:QSPI_RX_DATA register */
u32 dma_ctl; /* 020:QSPI_DMA_CTL register */
u32 dma_blk; /* 024:QSPI_DMA_BLK register */
u32 rsvd[56]; /* 028-107 reserved */
u32 tx_fifo; /* 108:QSPI_FIFO1 register */
u32 rsvd2[31]; /* 10c-187 reserved */
u32 rx_fifo; /* 188:QSPI_FIFO2 register */
u32 spare_ctl; /* 18c:QSPI_SPARE_CTRL register */
};
struct tegra210_qspi_priv {
struct qspi_regs *regs;
unsigned int freq;
unsigned int mode;
int periph_id;
int valid;
int last_transaction_us;
};
static int tegra210_qspi_ofdata_to_platdata(struct udevice *bus)
{
struct tegra_spi_platdata *plat = bus->platdata;
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
plat->base = dev_get_addr(bus);
plat->periph_id = clock_decode_periph_id(blob, node);
if (plat->periph_id == PERIPH_ID_NONE) {
debug("%s: could not decode periph id %d\n", __func__,
plat->periph_id);
return -FDT_ERR_NOTFOUND;
}
/* Use 500KHz as a suitable default */
plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
500000);
plat->deactivate_delay_us = fdtdec_get_int(blob, node,
"spi-deactivate-delay", 0);
debug("%s: base=%#08lx, periph_id=%d, max-frequency=%d, deactivate_delay=%d\n",
__func__, plat->base, plat->periph_id, plat->frequency,
plat->deactivate_delay_us);
return 0;
}
static int tegra210_qspi_probe(struct udevice *bus)
{
struct tegra_spi_platdata *plat = dev_get_platdata(bus);
struct tegra210_qspi_priv *priv = dev_get_priv(bus);
priv->regs = (struct qspi_regs *)plat->base;
priv->last_transaction_us = timer_get_us();
priv->freq = plat->frequency;
priv->periph_id = plat->periph_id;
return 0;
}
static int tegra210_qspi_claim_bus(struct udevice *bus)
{
struct tegra210_qspi_priv *priv = dev_get_priv(bus);
struct qspi_regs *regs = priv->regs;
/* Change SPI clock to correct frequency, PLLP_OUT0 source */
clock_start_periph_pll(priv->periph_id, CLOCK_ID_PERIPH, priv->freq);
debug("%s: FIFO STATUS = %08x\n", __func__, readl(&regs->fifo_status));
/* Set master mode and sw controlled CS */
setbits_le32(&regs->command1, QSPI_CMD1_M_S | QSPI_CMD1_CS_SW_HW |
(priv->mode << QSPI_CMD1_MODE_SHIFT));
debug("%s: COMMAND1 = %08x\n", __func__, readl(&regs->command1));
return 0;
}
/**
* Activate the CS by driving it LOW
*
* @param slave Pointer to spi_slave to which controller has to
* communicate with
*/
static void spi_cs_activate(struct udevice *dev)
{
struct udevice *bus = dev->parent;
struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
struct tegra210_qspi_priv *priv = dev_get_priv(bus);
/* If it's too soon to do another transaction, wait */
if (pdata->deactivate_delay_us &&
priv->last_transaction_us) {
ulong delay_us; /* The delay completed so far */
delay_us = timer_get_us() - priv->last_transaction_us;
if (delay_us < pdata->deactivate_delay_us)
udelay(pdata->deactivate_delay_us - delay_us);
}
clrbits_le32(&priv->regs->command1, QSPI_CMD1_CS_SW_VAL);
}
/**
* Deactivate the CS by driving it HIGH
*
* @param slave Pointer to spi_slave to which controller has to
* communicate with
*/
static void spi_cs_deactivate(struct udevice *dev)
{
struct udevice *bus = dev->parent;
struct tegra_spi_platdata *pdata = dev_get_platdata(bus);
struct tegra210_qspi_priv *priv = dev_get_priv(bus);
setbits_le32(&priv->regs->command1, QSPI_CMD1_CS_SW_VAL);
/* Remember time of this transaction so we can honour the bus delay */
if (pdata->deactivate_delay_us)
priv->last_transaction_us = timer_get_us();
debug("Deactivate CS, bus '%s'\n", bus->name);
}
static int tegra210_qspi_xfer(struct udevice *dev, unsigned int bitlen,
const void *data_out, void *data_in,
unsigned long flags)
{
struct udevice *bus = dev->parent;
struct tegra210_qspi_priv *priv = dev_get_priv(bus);
struct qspi_regs *regs = priv->regs;
u32 reg, tmpdout, tmpdin = 0;
const u8 *dout = data_out;
u8 *din = data_in;
int num_bytes, tm, ret;
debug("%s: slave %u:%u dout %p din %p bitlen %u\n",
__func__, bus->seq, spi_chip_select(dev), dout, din, bitlen);
if (bitlen % 8)
return -1;
num_bytes = bitlen / 8;
ret = 0;
/* clear all error status bits */
reg = readl(&regs->fifo_status);
writel(reg, &regs->fifo_status);
/* flush RX/TX FIFOs */
setbits_le32(&regs->fifo_status,
(QSPI_FIFO_STS_RX_FIFO_FLUSH |
QSPI_FIFO_STS_TX_FIFO_FLUSH));
tm = QSPI_TIMEOUT;
while ((tm && readl(&regs->fifo_status) &
(QSPI_FIFO_STS_RX_FIFO_FLUSH |
QSPI_FIFO_STS_TX_FIFO_FLUSH))) {
tm--;
udelay(1);
}
if (!tm) {
printf("%s: timeout during QSPI FIFO flush!\n",
__func__);
return -1;
}
/*
* Notes:
* 1. don't set LSBY_FE, so no need to swap bytes from/to TX/RX FIFOs;
* 2. don't set RX_EN and TX_EN yet.
* (SW needs to make sure that while programming the blk_size,
* tx_en and rx_en bits must be zero)
* [TODO] I (Yen Lin) have problems when both RX/TX EN bits are set
* i.e., both dout and din are not NULL.
*/
clrsetbits_le32(&regs->command1,
(QSPI_CMD1_LSBI_FE | QSPI_CMD1_LSBY_FE |
QSPI_CMD1_RX_EN | QSPI_CMD1_TX_EN),
(spi_chip_select(dev) << QSPI_CMD1_CS_SEL_SHIFT));
/* set xfer size to 1 block (32 bits) */
writel(0, &regs->dma_blk);
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(dev);
/* handle data in 32-bit chunks */
while (num_bytes > 0) {
int bytes;
tmpdout = 0;
bytes = (num_bytes > 4) ? 4 : num_bytes;
if (dout != NULL) {
memcpy((void *)&tmpdout, (void *)dout, bytes);
dout += bytes;
num_bytes -= bytes;
writel(tmpdout, &regs->tx_fifo);
setbits_le32(&regs->command1, QSPI_CMD1_TX_EN);
}
if (din != NULL)
setbits_le32(&regs->command1, QSPI_CMD1_RX_EN);
/* clear ready bit */
setbits_le32(&regs->xfer_status, QSPI_XFER_STS_RDY);
clrsetbits_le32(&regs->command1,
QSPI_CMD1_BITLEN_MASK << QSPI_CMD1_BITLEN_SHIFT,
(bytes * 8 - 1) << QSPI_CMD1_BITLEN_SHIFT);
/* Need to stabilize other reg bits before GO bit set.
* As per the TRM:
* "For successful operation at various freq combinations,
* a minimum of 4-5 spi_clk cycle delay might be required
* before enabling the PIO or DMA bits. The worst case delay
* calculation can be done considering slowest qspi_clk as
* 1MHz. Based on that 1us delay should be enough before
* enabling PIO or DMA." Padded another 1us for safety.
*/
udelay(2);
setbits_le32(&regs->command1, QSPI_CMD1_GO);
udelay(1);
/*
* Wait for SPI transmit FIFO to empty, or to time out.
* The RX FIFO status will be read and cleared last
*/
for (tm = 0; tm < QSPI_TIMEOUT; ++tm) {
u32 fifo_status, xfer_status;
xfer_status = readl(&regs->xfer_status);
if (!(xfer_status & QSPI_XFER_STS_RDY))
continue;
fifo_status = readl(&regs->fifo_status);
if (fifo_status & QSPI_FIFO_STS_ERR) {
debug("%s: got a fifo error: ", __func__);
if (fifo_status & QSPI_FIFO_STS_TX_FIFO_OVF)
debug("tx FIFO overflow ");
if (fifo_status & QSPI_FIFO_STS_TX_FIFO_UNR)
debug("tx FIFO underrun ");
if (fifo_status & QSPI_FIFO_STS_RX_FIFO_OVF)
debug("rx FIFO overflow ");
if (fifo_status & QSPI_FIFO_STS_RX_FIFO_UNR)
debug("rx FIFO underrun ");
if (fifo_status & QSPI_FIFO_STS_TX_FIFO_FULL)
debug("tx FIFO full ");
if (fifo_status & QSPI_FIFO_STS_TX_FIFO_EMPTY)
debug("tx FIFO empty ");
if (fifo_status & QSPI_FIFO_STS_RX_FIFO_FULL)
debug("rx FIFO full ");
if (fifo_status & QSPI_FIFO_STS_RX_FIFO_EMPTY)
debug("rx FIFO empty ");
debug("\n");
break;
}
if (!(fifo_status & QSPI_FIFO_STS_RX_FIFO_EMPTY)) {
tmpdin = readl(&regs->rx_fifo);
if (din != NULL) {
memcpy(din, &tmpdin, bytes);
din += bytes;
num_bytes -= bytes;
}
}
break;
}
if (tm >= QSPI_TIMEOUT)
ret = tm;
/* clear ACK RDY, etc. bits */
writel(readl(&regs->fifo_status), &regs->fifo_status);
}
if (flags & SPI_XFER_END)
spi_cs_deactivate(dev);
debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n",
__func__, tmpdin, readl(&regs->fifo_status));
if (ret) {
printf("%s: timeout during SPI transfer, tm %d\n",
__func__, ret);
return -1;
}
return ret;
}
static int tegra210_qspi_set_speed(struct udevice *bus, uint speed)
{
struct tegra_spi_platdata *plat = bus->platdata;
struct tegra210_qspi_priv *priv = dev_get_priv(bus);
if (speed > plat->frequency)
speed = plat->frequency;
priv->freq = speed;
debug("%s: regs=%p, speed=%d\n", __func__, priv->regs, priv->freq);
return 0;
}
static int tegra210_qspi_set_mode(struct udevice *bus, uint mode)
{
struct tegra210_qspi_priv *priv = dev_get_priv(bus);
priv->mode = mode;
debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode);
return 0;
}
static const struct dm_spi_ops tegra210_qspi_ops = {
.claim_bus = tegra210_qspi_claim_bus,
.xfer = tegra210_qspi_xfer,
.set_speed = tegra210_qspi_set_speed,
.set_mode = tegra210_qspi_set_mode,
/*
* cs_info is not needed, since we require all chip selects to be
* in the device tree explicitly
*/
};
static const struct udevice_id tegra210_qspi_ids[] = {
{ .compatible = "nvidia,tegra210-qspi" },
{ }
};
U_BOOT_DRIVER(tegra210_qspi) = {
.name = "tegra210-qspi",
.id = UCLASS_SPI,
.of_match = tegra210_qspi_ids,
.ops = &tegra210_qspi_ops,
.ofdata_to_platdata = tegra210_qspi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra210_qspi_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = tegra210_qspi_probe,
};

View file

@ -78,6 +78,4 @@
#define CONFIG_ARMV7_SECURE_BASE 0xfff00000
#define CONFIG_ARMV7_SECURE_RESERVE_SIZE 0x00100000
#define CONFIG_OF_BOARD_SETUP
#endif /* __CONFIG_H */

View file

@ -53,6 +53,16 @@
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX
/* PCI host support */
#define CONFIG_PCI
#define CONFIG_PCI_TEGRA
#define CONFIG_PCI_PNP
#define CONFIG_CMD_PCI
#define CONFIG_CMD_PCI_ENUM
/* PCI networking support */
#define CONFIG_RTL8169
/* General networking support */
#define CONFIG_CMD_DHCP

View file

@ -60,6 +60,4 @@
#include "tegra-common-usb-gadget.h"
#include "tegra-common-post.h"
#define CONFIG_OF_BOARD_SETUP
#endif /* _P2571_H */

View file

@ -143,4 +143,6 @@
#define CONFIG_FAT_WRITE
#endif
#define CONFIG_OF_SYSTEM_SETUP
#endif /* _TEGRA_COMMON_H_ */

View file

@ -60,6 +60,4 @@
#include "tegra-common-usb-gadget.h"
#include "tegra-common-post.h"
#define CONFIG_OF_BOARD_SETUP
#endif /* __CONFIG_H */

View file

@ -130,6 +130,7 @@ enum fdt_compat_id {
COMPAT_NVIDIA_TEGRA30_SDMMC, /* Tegra30 SDMMC controller */
COMPAT_NVIDIA_TEGRA20_SDMMC, /* Tegra20 SDMMC controller */
COMPAT_NVIDIA_TEGRA124_PCIE, /* Tegra 124 PCIe controller */
COMPAT_NVIDIA_TEGRA210_PCIE, /* Tegra 210 PCIe controller */
COMPAT_NVIDIA_TEGRA30_PCIE, /* Tegra 30 PCIe controller */
COMPAT_NVIDIA_TEGRA20_PCIE, /* Tegra 20 PCIe controller */
COMPAT_NVIDIA_TEGRA124_XUSB_PADCTL,

View file

@ -36,6 +36,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
COMPAT(NVIDIA_TEGRA124_PCIE, "nvidia,tegra124-pcie"),
COMPAT(NVIDIA_TEGRA210_PCIE, "nvidia,tegra210-pcie"),
COMPAT(NVIDIA_TEGRA30_PCIE, "nvidia,tegra30-pcie"),
COMPAT(NVIDIA_TEGRA20_PCIE, "nvidia,tegra20-pcie"),
COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"),