mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-20 17:08:52 +09:00
![Tom Rini](/assets/img/avatar_default.png)
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
311 lines
6.5 KiB
C
311 lines
6.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "tegra-xusb-padctl: " fmt
|
|
|
|
#include <common.h>
|
|
#include <errno.h>
|
|
|
|
#include "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,
|
|
ofnode node)
|
|
{
|
|
unsigned int i;
|
|
int len, ret;
|
|
|
|
group->name = ofnode_get_name(node);
|
|
|
|
len = ofnode_read_string_count(node, "nvidia,lanes");
|
|
if (len < 0) {
|
|
pr_err("failed to parse \"nvidia,lanes\" property");
|
|
return -EINVAL;
|
|
}
|
|
|
|
group->num_pins = len;
|
|
|
|
for (i = 0; i < group->num_pins; i++) {
|
|
ret = ofnode_read_string_index(node, "nvidia,lanes", i,
|
|
&group->pins[i]);
|
|
if (ret) {
|
|
pr_err("failed to read string from \"nvidia,lanes\" property");
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
group->num_pins = len;
|
|
|
|
ret = ofnode_read_string_index(node, "nvidia,function", 0,
|
|
&group->func);
|
|
if (ret) {
|
|
pr_err("failed to parse \"nvidia,func\" property");
|
|
return -EINVAL;
|
|
}
|
|
|
|
group->iddq = ofnode_read_u32_default(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) {
|
|
pr_err("no lane for pin %s", group->pins[i]);
|
|
continue;
|
|
}
|
|
|
|
func = tegra_xusb_padctl_lane_find_function(padctl, lane,
|
|
group->func);
|
|
if (func < 0) {
|
|
pr_err("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) {
|
|
pr_err("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,
|
|
ofnode node)
|
|
{
|
|
ofnode subnode;
|
|
|
|
config->name = ofnode_get_name(node);
|
|
|
|
ofnode_for_each_subnode(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, subnode);
|
|
if (err < 0) {
|
|
pr_err("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,
|
|
ofnode node)
|
|
{
|
|
ofnode subnode;
|
|
int err;
|
|
|
|
err = ofnode_read_resource(node, 0, &padctl->regs);
|
|
if (err < 0) {
|
|
pr_err("registers not found");
|
|
return err;
|
|
}
|
|
|
|
ofnode_for_each_subnode(subnode, node) {
|
|
struct tegra_xusb_padctl_config *config = &padctl->config;
|
|
|
|
debug("%s: subnode=%s\n", __func__, ofnode_get_name(subnode));
|
|
err = tegra_xusb_padctl_config_parse_dt(padctl, config,
|
|
subnode);
|
|
if (err < 0) {
|
|
pr_err("failed to parse entry %s: %d",
|
|
config->name, err);
|
|
continue;
|
|
}
|
|
}
|
|
debug("%s: done\n", __func__);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct tegra_xusb_padctl padctl;
|
|
|
|
int tegra_xusb_process_nodes(ofnode nodes[], unsigned int count,
|
|
const struct tegra_xusb_padctl_soc *socdata)
|
|
{
|
|
unsigned int i;
|
|
int err;
|
|
|
|
debug("%s: count=%d\n", __func__, count);
|
|
for (i = 0; i < count; i++) {
|
|
debug("%s: i=%d, node=%p\n", __func__, i, nodes[i].np);
|
|
if (!ofnode_is_available(nodes[i]))
|
|
continue;
|
|
|
|
padctl.socdata = socdata;
|
|
|
|
err = tegra_xusb_padctl_parse_dt(&padctl, nodes[i]);
|
|
if (err < 0) {
|
|
pr_err("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) {
|
|
pr_err("failed to apply pinmux: %d", err);
|
|
continue;
|
|
}
|
|
|
|
/* only a single instance is supported */
|
|
break;
|
|
}
|
|
debug("%s: done\n", __func__);
|
|
|
|
return 0;
|
|
}
|