11680d7b6SStephen Warren /* 21680d7b6SStephen Warren * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. 31680d7b6SStephen Warren * 41680d7b6SStephen Warren * SPDX-License-Identifier: GPL-2.0 51680d7b6SStephen Warren */ 61680d7b6SStephen Warren 71680d7b6SStephen Warren #define pr_fmt(fmt) "tegra-xusb-padctl: " fmt 81680d7b6SStephen Warren 91680d7b6SStephen Warren #include <common.h> 101680d7b6SStephen Warren #include <errno.h> 111680d7b6SStephen Warren 121680d7b6SStephen Warren #include "xusb-padctl-common.h" 131680d7b6SStephen Warren 141680d7b6SStephen Warren #include <asm/arch/clock.h> 151680d7b6SStephen Warren 161680d7b6SStephen Warren int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy) 171680d7b6SStephen Warren { 181680d7b6SStephen Warren if (phy && phy->ops && phy->ops->prepare) 191680d7b6SStephen Warren return phy->ops->prepare(phy); 201680d7b6SStephen Warren 211680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 221680d7b6SStephen Warren } 231680d7b6SStephen Warren 241680d7b6SStephen Warren int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy) 251680d7b6SStephen Warren { 261680d7b6SStephen Warren if (phy && phy->ops && phy->ops->enable) 271680d7b6SStephen Warren return phy->ops->enable(phy); 281680d7b6SStephen Warren 291680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 301680d7b6SStephen Warren } 311680d7b6SStephen Warren 321680d7b6SStephen Warren int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy) 331680d7b6SStephen Warren { 341680d7b6SStephen Warren if (phy && phy->ops && phy->ops->disable) 351680d7b6SStephen Warren return phy->ops->disable(phy); 361680d7b6SStephen Warren 371680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 381680d7b6SStephen Warren } 391680d7b6SStephen Warren 401680d7b6SStephen Warren int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy) 411680d7b6SStephen Warren { 421680d7b6SStephen Warren if (phy && phy->ops && phy->ops->unprepare) 431680d7b6SStephen Warren return phy->ops->unprepare(phy); 441680d7b6SStephen Warren 451680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 461680d7b6SStephen Warren } 471680d7b6SStephen Warren 481680d7b6SStephen Warren struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type) 491680d7b6SStephen Warren { 501680d7b6SStephen Warren struct tegra_xusb_phy *phy; 511680d7b6SStephen Warren int i; 521680d7b6SStephen Warren 531680d7b6SStephen Warren for (i = 0; i < padctl.socdata->num_phys; i++) { 541680d7b6SStephen Warren phy = &padctl.socdata->phys[i]; 551680d7b6SStephen Warren if (phy->type != type) 561680d7b6SStephen Warren continue; 571680d7b6SStephen Warren return phy; 581680d7b6SStephen Warren } 591680d7b6SStephen Warren 601680d7b6SStephen Warren return NULL; 611680d7b6SStephen Warren } 621680d7b6SStephen Warren 631680d7b6SStephen Warren static const struct tegra_xusb_padctl_lane * 641680d7b6SStephen Warren tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name) 651680d7b6SStephen Warren { 661680d7b6SStephen Warren unsigned int i; 671680d7b6SStephen Warren 681680d7b6SStephen Warren for (i = 0; i < padctl->socdata->num_lanes; i++) 691680d7b6SStephen Warren if (strcmp(name, padctl->socdata->lanes[i].name) == 0) 701680d7b6SStephen Warren return &padctl->socdata->lanes[i]; 711680d7b6SStephen Warren 721680d7b6SStephen Warren return NULL; 731680d7b6SStephen Warren } 741680d7b6SStephen Warren 751680d7b6SStephen Warren static int 761680d7b6SStephen Warren tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl, 771680d7b6SStephen Warren struct tegra_xusb_padctl_group *group, 78be789092SSimon Glass ofnode node) 791680d7b6SStephen Warren { 801680d7b6SStephen Warren unsigned int i; 81be789092SSimon Glass int len, ret; 821680d7b6SStephen Warren 83be789092SSimon Glass group->name = ofnode_get_name(node); 841680d7b6SStephen Warren 85be789092SSimon Glass len = ofnode_read_string_count(node, "nvidia,lanes"); 861680d7b6SStephen Warren if (len < 0) { 871680d7b6SStephen Warren error("failed to parse \"nvidia,lanes\" property"); 881680d7b6SStephen Warren return -EINVAL; 891680d7b6SStephen Warren } 901680d7b6SStephen Warren 911680d7b6SStephen Warren group->num_pins = len; 921680d7b6SStephen Warren 931680d7b6SStephen Warren for (i = 0; i < group->num_pins; i++) { 94be789092SSimon Glass ret = ofnode_read_string_index(node, "nvidia,lanes", i, 95be789092SSimon Glass &group->pins[i]); 96be789092SSimon Glass if (ret) { 971680d7b6SStephen Warren error("failed to read string from \"nvidia,lanes\" property"); 981680d7b6SStephen Warren return -EINVAL; 991680d7b6SStephen Warren } 1001680d7b6SStephen Warren } 1011680d7b6SStephen Warren 1021680d7b6SStephen Warren group->num_pins = len; 1031680d7b6SStephen Warren 104be789092SSimon Glass ret = ofnode_read_string_index(node, "nvidia,function", 0, 105be789092SSimon Glass &group->func); 106be789092SSimon Glass if (ret) { 1071680d7b6SStephen Warren error("failed to parse \"nvidia,func\" property"); 1081680d7b6SStephen Warren return -EINVAL; 1091680d7b6SStephen Warren } 1101680d7b6SStephen Warren 111be789092SSimon Glass group->iddq = ofnode_read_u32_default(node, "nvidia,iddq", -1); 1121680d7b6SStephen Warren 1131680d7b6SStephen Warren return 0; 1141680d7b6SStephen Warren } 1151680d7b6SStephen Warren 1161680d7b6SStephen Warren static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl, 1171680d7b6SStephen Warren const char *name) 1181680d7b6SStephen Warren { 1191680d7b6SStephen Warren unsigned int i; 1201680d7b6SStephen Warren 1211680d7b6SStephen Warren for (i = 0; i < padctl->socdata->num_functions; i++) 1221680d7b6SStephen Warren if (strcmp(name, padctl->socdata->functions[i]) == 0) 1231680d7b6SStephen Warren return i; 1241680d7b6SStephen Warren 1251680d7b6SStephen Warren return -ENOENT; 1261680d7b6SStephen Warren } 1271680d7b6SStephen Warren 1281680d7b6SStephen Warren static int 1291680d7b6SStephen Warren tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl, 1301680d7b6SStephen Warren const struct tegra_xusb_padctl_lane *lane, 1311680d7b6SStephen Warren const char *name) 1321680d7b6SStephen Warren { 1331680d7b6SStephen Warren unsigned int i; 1341680d7b6SStephen Warren int func; 1351680d7b6SStephen Warren 1361680d7b6SStephen Warren func = tegra_xusb_padctl_find_function(padctl, name); 1371680d7b6SStephen Warren if (func < 0) 1381680d7b6SStephen Warren return func; 1391680d7b6SStephen Warren 1401680d7b6SStephen Warren for (i = 0; i < lane->num_funcs; i++) 1411680d7b6SStephen Warren if (lane->funcs[i] == func) 1421680d7b6SStephen Warren return i; 1431680d7b6SStephen Warren 1441680d7b6SStephen Warren return -ENOENT; 1451680d7b6SStephen Warren } 1461680d7b6SStephen Warren 1471680d7b6SStephen Warren static int 1481680d7b6SStephen Warren tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl, 1491680d7b6SStephen Warren const struct tegra_xusb_padctl_group *group) 1501680d7b6SStephen Warren { 1511680d7b6SStephen Warren unsigned int i; 1521680d7b6SStephen Warren 1531680d7b6SStephen Warren for (i = 0; i < group->num_pins; i++) { 1541680d7b6SStephen Warren const struct tegra_xusb_padctl_lane *lane; 1551680d7b6SStephen Warren unsigned int func; 1561680d7b6SStephen Warren u32 value; 1571680d7b6SStephen Warren 1581680d7b6SStephen Warren lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]); 1591680d7b6SStephen Warren if (!lane) { 1601680d7b6SStephen Warren error("no lane for pin %s", group->pins[i]); 1611680d7b6SStephen Warren continue; 1621680d7b6SStephen Warren } 1631680d7b6SStephen Warren 1641680d7b6SStephen Warren func = tegra_xusb_padctl_lane_find_function(padctl, lane, 1651680d7b6SStephen Warren group->func); 1661680d7b6SStephen Warren if (func < 0) { 1671680d7b6SStephen Warren error("function %s invalid for lane %s: %d", 1681680d7b6SStephen Warren group->func, lane->name, func); 1691680d7b6SStephen Warren continue; 1701680d7b6SStephen Warren } 1711680d7b6SStephen Warren 1721680d7b6SStephen Warren value = padctl_readl(padctl, lane->offset); 1731680d7b6SStephen Warren 1741680d7b6SStephen Warren /* set pin function */ 1751680d7b6SStephen Warren value &= ~(lane->mask << lane->shift); 1761680d7b6SStephen Warren value |= func << lane->shift; 1771680d7b6SStephen Warren 1781680d7b6SStephen Warren /* 1791680d7b6SStephen Warren * Set IDDQ if supported on the lane and specified in the 1801680d7b6SStephen Warren * configuration. 1811680d7b6SStephen Warren */ 1821680d7b6SStephen Warren if (lane->iddq > 0 && group->iddq >= 0) { 1831680d7b6SStephen Warren if (group->iddq != 0) 1841680d7b6SStephen Warren value &= ~(1 << lane->iddq); 1851680d7b6SStephen Warren else 1861680d7b6SStephen Warren value |= 1 << lane->iddq; 1871680d7b6SStephen Warren } 1881680d7b6SStephen Warren 1891680d7b6SStephen Warren padctl_writel(padctl, value, lane->offset); 1901680d7b6SStephen Warren } 1911680d7b6SStephen Warren 1921680d7b6SStephen Warren return 0; 1931680d7b6SStephen Warren } 1941680d7b6SStephen Warren 1951680d7b6SStephen Warren static int 1961680d7b6SStephen Warren tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl, 1971680d7b6SStephen Warren struct tegra_xusb_padctl_config *config) 1981680d7b6SStephen Warren { 1991680d7b6SStephen Warren unsigned int i; 2001680d7b6SStephen Warren 2011680d7b6SStephen Warren for (i = 0; i < config->num_groups; i++) { 2021680d7b6SStephen Warren const struct tegra_xusb_padctl_group *group; 2031680d7b6SStephen Warren int err; 2041680d7b6SStephen Warren 2051680d7b6SStephen Warren group = &config->groups[i]; 2061680d7b6SStephen Warren 2071680d7b6SStephen Warren err = tegra_xusb_padctl_group_apply(padctl, group); 2081680d7b6SStephen Warren if (err < 0) { 2091680d7b6SStephen Warren error("failed to apply group %s: %d", 2101680d7b6SStephen Warren group->name, err); 2111680d7b6SStephen Warren continue; 2121680d7b6SStephen Warren } 2131680d7b6SStephen Warren } 2141680d7b6SStephen Warren 2151680d7b6SStephen Warren return 0; 2161680d7b6SStephen Warren } 2171680d7b6SStephen Warren 2181680d7b6SStephen Warren static int 2191680d7b6SStephen Warren tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl, 2201680d7b6SStephen Warren struct tegra_xusb_padctl_config *config, 221be789092SSimon Glass ofnode node) 2221680d7b6SStephen Warren { 223be789092SSimon Glass ofnode subnode; 2241680d7b6SStephen Warren 225be789092SSimon Glass config->name = ofnode_get_name(node); 2261680d7b6SStephen Warren 227*17c82fdcSSimon Glass ofnode_for_each_subnode(subnode, node) { 2281680d7b6SStephen Warren struct tegra_xusb_padctl_group *group; 2291680d7b6SStephen Warren int err; 2301680d7b6SStephen Warren 2311680d7b6SStephen Warren group = &config->groups[config->num_groups]; 2321680d7b6SStephen Warren 233be789092SSimon Glass err = tegra_xusb_padctl_group_parse_dt(padctl, group, subnode); 2341680d7b6SStephen Warren if (err < 0) { 2351680d7b6SStephen Warren error("failed to parse group %s", group->name); 2361680d7b6SStephen Warren return err; 2371680d7b6SStephen Warren } 2381680d7b6SStephen Warren 2391680d7b6SStephen Warren config->num_groups++; 2401680d7b6SStephen Warren } 2411680d7b6SStephen Warren 2421680d7b6SStephen Warren return 0; 2431680d7b6SStephen Warren } 2441680d7b6SStephen Warren 2451680d7b6SStephen Warren static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl, 246be789092SSimon Glass ofnode node) 2471680d7b6SStephen Warren { 248be789092SSimon Glass ofnode subnode; 249be789092SSimon Glass int err; 2501680d7b6SStephen Warren 251be789092SSimon Glass err = ofnode_read_resource(node, 0, &padctl->regs); 2521680d7b6SStephen Warren if (err < 0) { 2531680d7b6SStephen Warren error("registers not found"); 2541680d7b6SStephen Warren return err; 2551680d7b6SStephen Warren } 2561680d7b6SStephen Warren 257*17c82fdcSSimon Glass ofnode_for_each_subnode(subnode, node) { 2581680d7b6SStephen Warren struct tegra_xusb_padctl_config *config = &padctl->config; 2591680d7b6SStephen Warren 260be789092SSimon Glass debug("%s: subnode=%s\n", __func__, ofnode_get_name(subnode)); 261be789092SSimon Glass err = tegra_xusb_padctl_config_parse_dt(padctl, config, 2621680d7b6SStephen Warren subnode); 2631680d7b6SStephen Warren if (err < 0) { 2641680d7b6SStephen Warren error("failed to parse entry %s: %d", 2651680d7b6SStephen Warren config->name, err); 2661680d7b6SStephen Warren continue; 2671680d7b6SStephen Warren } 2681680d7b6SStephen Warren } 269be789092SSimon Glass debug("%s: done\n", __func__); 2701680d7b6SStephen Warren 2711680d7b6SStephen Warren return 0; 2721680d7b6SStephen Warren } 2731680d7b6SStephen Warren 2741680d7b6SStephen Warren struct tegra_xusb_padctl padctl; 2751680d7b6SStephen Warren 276be789092SSimon Glass int tegra_xusb_process_nodes(ofnode nodes[], unsigned int count, 2771680d7b6SStephen Warren const struct tegra_xusb_padctl_soc *socdata) 2781680d7b6SStephen Warren { 2791680d7b6SStephen Warren unsigned int i; 2801680d7b6SStephen Warren int err; 2811680d7b6SStephen Warren 282be789092SSimon Glass debug("%s: count=%d\n", __func__, count); 2831680d7b6SStephen Warren for (i = 0; i < count; i++) { 284be789092SSimon Glass debug("%s: i=%d, node=%p\n", __func__, i, nodes[i].np); 285be789092SSimon Glass if (!ofnode_is_available(nodes[i])) 2861680d7b6SStephen Warren continue; 2871680d7b6SStephen Warren 2881680d7b6SStephen Warren padctl.socdata = socdata; 2891680d7b6SStephen Warren 290be789092SSimon Glass err = tegra_xusb_padctl_parse_dt(&padctl, nodes[i]); 2911680d7b6SStephen Warren if (err < 0) { 2921680d7b6SStephen Warren error("failed to parse DT: %d", err); 2931680d7b6SStephen Warren continue; 2941680d7b6SStephen Warren } 2951680d7b6SStephen Warren 2961680d7b6SStephen Warren /* deassert XUSB padctl reset */ 2971680d7b6SStephen Warren reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0); 2981680d7b6SStephen Warren 2991680d7b6SStephen Warren err = tegra_xusb_padctl_config_apply(&padctl, &padctl.config); 3001680d7b6SStephen Warren if (err < 0) { 3011680d7b6SStephen Warren error("failed to apply pinmux: %d", err); 3021680d7b6SStephen Warren continue; 3031680d7b6SStephen Warren } 3041680d7b6SStephen Warren 3051680d7b6SStephen Warren /* only a single instance is supported */ 3061680d7b6SStephen Warren break; 3071680d7b6SStephen Warren } 308be789092SSimon Glass debug("%s: done\n", __func__); 3091680d7b6SStephen Warren 3101680d7b6SStephen Warren return 0; 3111680d7b6SStephen Warren } 312