mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-tegra
This commit is contained in:
commit
bc80109b11
30 changed files with 1355 additions and 671 deletions
|
@ -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>;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__);
|
||||
|
|
305
arch/arm/mach-tegra/xusb-padctl-common.c
Normal file
305
arch/arm/mach-tegra/xusb-padctl-common.c
Normal 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;
|
||||
}
|
101
arch/arm/mach-tegra/xusb-padctl-common.h
Normal file
101
arch/arm/mach-tegra/xusb-padctl-common.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
417
drivers/spi/tegra210_qspi.c
Normal 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(®s->fifo_status));
|
||||
|
||||
/* Set master mode and sw controlled CS */
|
||||
setbits_le32(®s->command1, QSPI_CMD1_M_S | QSPI_CMD1_CS_SW_HW |
|
||||
(priv->mode << QSPI_CMD1_MODE_SHIFT));
|
||||
debug("%s: COMMAND1 = %08x\n", __func__, readl(®s->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(®s->fifo_status);
|
||||
writel(reg, ®s->fifo_status);
|
||||
|
||||
/* flush RX/TX FIFOs */
|
||||
setbits_le32(®s->fifo_status,
|
||||
(QSPI_FIFO_STS_RX_FIFO_FLUSH |
|
||||
QSPI_FIFO_STS_TX_FIFO_FLUSH));
|
||||
|
||||
tm = QSPI_TIMEOUT;
|
||||
while ((tm && readl(®s->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(®s->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, ®s->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, ®s->tx_fifo);
|
||||
setbits_le32(®s->command1, QSPI_CMD1_TX_EN);
|
||||
}
|
||||
|
||||
if (din != NULL)
|
||||
setbits_le32(®s->command1, QSPI_CMD1_RX_EN);
|
||||
|
||||
/* clear ready bit */
|
||||
setbits_le32(®s->xfer_status, QSPI_XFER_STS_RDY);
|
||||
|
||||
clrsetbits_le32(®s->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(®s->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(®s->xfer_status);
|
||||
if (!(xfer_status & QSPI_XFER_STS_RDY))
|
||||
continue;
|
||||
|
||||
fifo_status = readl(®s->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(®s->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(®s->fifo_status), ®s->fifo_status);
|
||||
}
|
||||
|
||||
if (flags & SPI_XFER_END)
|
||||
spi_cs_deactivate(dev);
|
||||
|
||||
debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n",
|
||||
__func__, tmpdin, readl(®s->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,
|
||||
};
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -60,6 +60,4 @@
|
|||
#include "tegra-common-usb-gadget.h"
|
||||
#include "tegra-common-post.h"
|
||||
|
||||
#define CONFIG_OF_BOARD_SETUP
|
||||
|
||||
#endif /* _P2571_H */
|
||||
|
|
|
@ -143,4 +143,6 @@
|
|||
#define CONFIG_FAT_WRITE
|
||||
#endif
|
||||
|
||||
#define CONFIG_OF_SYSTEM_SETUP
|
||||
|
||||
#endif /* _TEGRA_COMMON_H_ */
|
||||
|
|
|
@ -60,6 +60,4 @@
|
|||
#include "tegra-common-usb-gadget.h"
|
||||
#include "tegra-common-post.h"
|
||||
|
||||
#define CONFIG_OF_BOARD_SETUP
|
||||
|
||||
#endif /* __CONFIG_H */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"),
|
||||
|
|
Loading…
Reference in a new issue