1*1680d7b6SStephen Warren /* 2*1680d7b6SStephen Warren * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. 3*1680d7b6SStephen Warren * 4*1680d7b6SStephen Warren * SPDX-License-Identifier: GPL-2.0 5*1680d7b6SStephen Warren */ 6*1680d7b6SStephen Warren 7*1680d7b6SStephen Warren #define pr_fmt(fmt) "tegra-xusb-padctl: " fmt 8*1680d7b6SStephen Warren 9*1680d7b6SStephen Warren #include <common.h> 10*1680d7b6SStephen Warren #include <errno.h> 11*1680d7b6SStephen Warren 12*1680d7b6SStephen Warren #include "xusb-padctl-common.h" 13*1680d7b6SStephen Warren 14*1680d7b6SStephen Warren #include <asm/arch/clock.h> 15*1680d7b6SStephen Warren 16*1680d7b6SStephen Warren int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy) 17*1680d7b6SStephen Warren { 18*1680d7b6SStephen Warren if (phy && phy->ops && phy->ops->prepare) 19*1680d7b6SStephen Warren return phy->ops->prepare(phy); 20*1680d7b6SStephen Warren 21*1680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 22*1680d7b6SStephen Warren } 23*1680d7b6SStephen Warren 24*1680d7b6SStephen Warren int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy) 25*1680d7b6SStephen Warren { 26*1680d7b6SStephen Warren if (phy && phy->ops && phy->ops->enable) 27*1680d7b6SStephen Warren return phy->ops->enable(phy); 28*1680d7b6SStephen Warren 29*1680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 30*1680d7b6SStephen Warren } 31*1680d7b6SStephen Warren 32*1680d7b6SStephen Warren int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy) 33*1680d7b6SStephen Warren { 34*1680d7b6SStephen Warren if (phy && phy->ops && phy->ops->disable) 35*1680d7b6SStephen Warren return phy->ops->disable(phy); 36*1680d7b6SStephen Warren 37*1680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 38*1680d7b6SStephen Warren } 39*1680d7b6SStephen Warren 40*1680d7b6SStephen Warren int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy) 41*1680d7b6SStephen Warren { 42*1680d7b6SStephen Warren if (phy && phy->ops && phy->ops->unprepare) 43*1680d7b6SStephen Warren return phy->ops->unprepare(phy); 44*1680d7b6SStephen Warren 45*1680d7b6SStephen Warren return phy ? -ENOSYS : -EINVAL; 46*1680d7b6SStephen Warren } 47*1680d7b6SStephen Warren 48*1680d7b6SStephen Warren struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type) 49*1680d7b6SStephen Warren { 50*1680d7b6SStephen Warren struct tegra_xusb_phy *phy; 51*1680d7b6SStephen Warren int i; 52*1680d7b6SStephen Warren 53*1680d7b6SStephen Warren for (i = 0; i < padctl.socdata->num_phys; i++) { 54*1680d7b6SStephen Warren phy = &padctl.socdata->phys[i]; 55*1680d7b6SStephen Warren if (phy->type != type) 56*1680d7b6SStephen Warren continue; 57*1680d7b6SStephen Warren return phy; 58*1680d7b6SStephen Warren } 59*1680d7b6SStephen Warren 60*1680d7b6SStephen Warren return NULL; 61*1680d7b6SStephen Warren } 62*1680d7b6SStephen Warren 63*1680d7b6SStephen Warren static const struct tegra_xusb_padctl_lane * 64*1680d7b6SStephen Warren tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name) 65*1680d7b6SStephen Warren { 66*1680d7b6SStephen Warren unsigned int i; 67*1680d7b6SStephen Warren 68*1680d7b6SStephen Warren for (i = 0; i < padctl->socdata->num_lanes; i++) 69*1680d7b6SStephen Warren if (strcmp(name, padctl->socdata->lanes[i].name) == 0) 70*1680d7b6SStephen Warren return &padctl->socdata->lanes[i]; 71*1680d7b6SStephen Warren 72*1680d7b6SStephen Warren return NULL; 73*1680d7b6SStephen Warren } 74*1680d7b6SStephen Warren 75*1680d7b6SStephen Warren static int 76*1680d7b6SStephen Warren tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl, 77*1680d7b6SStephen Warren struct tegra_xusb_padctl_group *group, 78*1680d7b6SStephen Warren const void *fdt, int node) 79*1680d7b6SStephen Warren { 80*1680d7b6SStephen Warren unsigned int i; 81*1680d7b6SStephen Warren int len, err; 82*1680d7b6SStephen Warren 83*1680d7b6SStephen Warren group->name = fdt_get_name(fdt, node, &len); 84*1680d7b6SStephen Warren 85*1680d7b6SStephen Warren len = fdt_count_strings(fdt, node, "nvidia,lanes"); 86*1680d7b6SStephen Warren if (len < 0) { 87*1680d7b6SStephen Warren error("failed to parse \"nvidia,lanes\" property"); 88*1680d7b6SStephen Warren return -EINVAL; 89*1680d7b6SStephen Warren } 90*1680d7b6SStephen Warren 91*1680d7b6SStephen Warren group->num_pins = len; 92*1680d7b6SStephen Warren 93*1680d7b6SStephen Warren for (i = 0; i < group->num_pins; i++) { 94*1680d7b6SStephen Warren err = fdt_get_string_index(fdt, node, "nvidia,lanes", i, 95*1680d7b6SStephen Warren &group->pins[i]); 96*1680d7b6SStephen Warren if (err < 0) { 97*1680d7b6SStephen Warren error("failed to read string from \"nvidia,lanes\" property"); 98*1680d7b6SStephen Warren return -EINVAL; 99*1680d7b6SStephen Warren } 100*1680d7b6SStephen Warren } 101*1680d7b6SStephen Warren 102*1680d7b6SStephen Warren group->num_pins = len; 103*1680d7b6SStephen Warren 104*1680d7b6SStephen Warren err = fdt_get_string(fdt, node, "nvidia,function", &group->func); 105*1680d7b6SStephen Warren if (err < 0) { 106*1680d7b6SStephen Warren error("failed to parse \"nvidia,func\" property"); 107*1680d7b6SStephen Warren return -EINVAL; 108*1680d7b6SStephen Warren } 109*1680d7b6SStephen Warren 110*1680d7b6SStephen Warren group->iddq = fdtdec_get_int(fdt, node, "nvidia,iddq", -1); 111*1680d7b6SStephen Warren 112*1680d7b6SStephen Warren return 0; 113*1680d7b6SStephen Warren } 114*1680d7b6SStephen Warren 115*1680d7b6SStephen Warren static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl, 116*1680d7b6SStephen Warren const char *name) 117*1680d7b6SStephen Warren { 118*1680d7b6SStephen Warren unsigned int i; 119*1680d7b6SStephen Warren 120*1680d7b6SStephen Warren for (i = 0; i < padctl->socdata->num_functions; i++) 121*1680d7b6SStephen Warren if (strcmp(name, padctl->socdata->functions[i]) == 0) 122*1680d7b6SStephen Warren return i; 123*1680d7b6SStephen Warren 124*1680d7b6SStephen Warren return -ENOENT; 125*1680d7b6SStephen Warren } 126*1680d7b6SStephen Warren 127*1680d7b6SStephen Warren static int 128*1680d7b6SStephen Warren tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl, 129*1680d7b6SStephen Warren const struct tegra_xusb_padctl_lane *lane, 130*1680d7b6SStephen Warren const char *name) 131*1680d7b6SStephen Warren { 132*1680d7b6SStephen Warren unsigned int i; 133*1680d7b6SStephen Warren int func; 134*1680d7b6SStephen Warren 135*1680d7b6SStephen Warren func = tegra_xusb_padctl_find_function(padctl, name); 136*1680d7b6SStephen Warren if (func < 0) 137*1680d7b6SStephen Warren return func; 138*1680d7b6SStephen Warren 139*1680d7b6SStephen Warren for (i = 0; i < lane->num_funcs; i++) 140*1680d7b6SStephen Warren if (lane->funcs[i] == func) 141*1680d7b6SStephen Warren return i; 142*1680d7b6SStephen Warren 143*1680d7b6SStephen Warren return -ENOENT; 144*1680d7b6SStephen Warren } 145*1680d7b6SStephen Warren 146*1680d7b6SStephen Warren static int 147*1680d7b6SStephen Warren tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl, 148*1680d7b6SStephen Warren const struct tegra_xusb_padctl_group *group) 149*1680d7b6SStephen Warren { 150*1680d7b6SStephen Warren unsigned int i; 151*1680d7b6SStephen Warren 152*1680d7b6SStephen Warren for (i = 0; i < group->num_pins; i++) { 153*1680d7b6SStephen Warren const struct tegra_xusb_padctl_lane *lane; 154*1680d7b6SStephen Warren unsigned int func; 155*1680d7b6SStephen Warren u32 value; 156*1680d7b6SStephen Warren 157*1680d7b6SStephen Warren lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]); 158*1680d7b6SStephen Warren if (!lane) { 159*1680d7b6SStephen Warren error("no lane for pin %s", group->pins[i]); 160*1680d7b6SStephen Warren continue; 161*1680d7b6SStephen Warren } 162*1680d7b6SStephen Warren 163*1680d7b6SStephen Warren func = tegra_xusb_padctl_lane_find_function(padctl, lane, 164*1680d7b6SStephen Warren group->func); 165*1680d7b6SStephen Warren if (func < 0) { 166*1680d7b6SStephen Warren error("function %s invalid for lane %s: %d", 167*1680d7b6SStephen Warren group->func, lane->name, func); 168*1680d7b6SStephen Warren continue; 169*1680d7b6SStephen Warren } 170*1680d7b6SStephen Warren 171*1680d7b6SStephen Warren value = padctl_readl(padctl, lane->offset); 172*1680d7b6SStephen Warren 173*1680d7b6SStephen Warren /* set pin function */ 174*1680d7b6SStephen Warren value &= ~(lane->mask << lane->shift); 175*1680d7b6SStephen Warren value |= func << lane->shift; 176*1680d7b6SStephen Warren 177*1680d7b6SStephen Warren /* 178*1680d7b6SStephen Warren * Set IDDQ if supported on the lane and specified in the 179*1680d7b6SStephen Warren * configuration. 180*1680d7b6SStephen Warren */ 181*1680d7b6SStephen Warren if (lane->iddq > 0 && group->iddq >= 0) { 182*1680d7b6SStephen Warren if (group->iddq != 0) 183*1680d7b6SStephen Warren value &= ~(1 << lane->iddq); 184*1680d7b6SStephen Warren else 185*1680d7b6SStephen Warren value |= 1 << lane->iddq; 186*1680d7b6SStephen Warren } 187*1680d7b6SStephen Warren 188*1680d7b6SStephen Warren padctl_writel(padctl, value, lane->offset); 189*1680d7b6SStephen Warren } 190*1680d7b6SStephen Warren 191*1680d7b6SStephen Warren return 0; 192*1680d7b6SStephen Warren } 193*1680d7b6SStephen Warren 194*1680d7b6SStephen Warren static int 195*1680d7b6SStephen Warren tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl, 196*1680d7b6SStephen Warren struct tegra_xusb_padctl_config *config) 197*1680d7b6SStephen Warren { 198*1680d7b6SStephen Warren unsigned int i; 199*1680d7b6SStephen Warren 200*1680d7b6SStephen Warren for (i = 0; i < config->num_groups; i++) { 201*1680d7b6SStephen Warren const struct tegra_xusb_padctl_group *group; 202*1680d7b6SStephen Warren int err; 203*1680d7b6SStephen Warren 204*1680d7b6SStephen Warren group = &config->groups[i]; 205*1680d7b6SStephen Warren 206*1680d7b6SStephen Warren err = tegra_xusb_padctl_group_apply(padctl, group); 207*1680d7b6SStephen Warren if (err < 0) { 208*1680d7b6SStephen Warren error("failed to apply group %s: %d", 209*1680d7b6SStephen Warren group->name, err); 210*1680d7b6SStephen Warren continue; 211*1680d7b6SStephen Warren } 212*1680d7b6SStephen Warren } 213*1680d7b6SStephen Warren 214*1680d7b6SStephen Warren return 0; 215*1680d7b6SStephen Warren } 216*1680d7b6SStephen Warren 217*1680d7b6SStephen Warren static int 218*1680d7b6SStephen Warren tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl, 219*1680d7b6SStephen Warren struct tegra_xusb_padctl_config *config, 220*1680d7b6SStephen Warren const void *fdt, int node) 221*1680d7b6SStephen Warren { 222*1680d7b6SStephen Warren int subnode; 223*1680d7b6SStephen Warren 224*1680d7b6SStephen Warren config->name = fdt_get_name(fdt, node, NULL); 225*1680d7b6SStephen Warren 226*1680d7b6SStephen Warren fdt_for_each_subnode(fdt, subnode, node) { 227*1680d7b6SStephen Warren struct tegra_xusb_padctl_group *group; 228*1680d7b6SStephen Warren int err; 229*1680d7b6SStephen Warren 230*1680d7b6SStephen Warren group = &config->groups[config->num_groups]; 231*1680d7b6SStephen Warren 232*1680d7b6SStephen Warren err = tegra_xusb_padctl_group_parse_dt(padctl, group, fdt, 233*1680d7b6SStephen Warren subnode); 234*1680d7b6SStephen Warren if (err < 0) { 235*1680d7b6SStephen Warren error("failed to parse group %s", group->name); 236*1680d7b6SStephen Warren return err; 237*1680d7b6SStephen Warren } 238*1680d7b6SStephen Warren 239*1680d7b6SStephen Warren config->num_groups++; 240*1680d7b6SStephen Warren } 241*1680d7b6SStephen Warren 242*1680d7b6SStephen Warren return 0; 243*1680d7b6SStephen Warren } 244*1680d7b6SStephen Warren 245*1680d7b6SStephen Warren static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl, 246*1680d7b6SStephen Warren const void *fdt, int node) 247*1680d7b6SStephen Warren { 248*1680d7b6SStephen Warren int subnode, err; 249*1680d7b6SStephen Warren 250*1680d7b6SStephen Warren err = fdt_get_resource(fdt, node, "reg", 0, &padctl->regs); 251*1680d7b6SStephen Warren if (err < 0) { 252*1680d7b6SStephen Warren error("registers not found"); 253*1680d7b6SStephen Warren return err; 254*1680d7b6SStephen Warren } 255*1680d7b6SStephen Warren 256*1680d7b6SStephen Warren fdt_for_each_subnode(fdt, subnode, node) { 257*1680d7b6SStephen Warren struct tegra_xusb_padctl_config *config = &padctl->config; 258*1680d7b6SStephen Warren 259*1680d7b6SStephen Warren err = tegra_xusb_padctl_config_parse_dt(padctl, config, fdt, 260*1680d7b6SStephen Warren subnode); 261*1680d7b6SStephen Warren if (err < 0) { 262*1680d7b6SStephen Warren error("failed to parse entry %s: %d", 263*1680d7b6SStephen Warren config->name, err); 264*1680d7b6SStephen Warren continue; 265*1680d7b6SStephen Warren } 266*1680d7b6SStephen Warren } 267*1680d7b6SStephen Warren 268*1680d7b6SStephen Warren return 0; 269*1680d7b6SStephen Warren } 270*1680d7b6SStephen Warren 271*1680d7b6SStephen Warren struct tegra_xusb_padctl padctl; 272*1680d7b6SStephen Warren 273*1680d7b6SStephen Warren int tegra_xusb_process_nodes(const void *fdt, int nodes[], unsigned int count, 274*1680d7b6SStephen Warren const struct tegra_xusb_padctl_soc *socdata) 275*1680d7b6SStephen Warren { 276*1680d7b6SStephen Warren unsigned int i; 277*1680d7b6SStephen Warren int err; 278*1680d7b6SStephen Warren 279*1680d7b6SStephen Warren for (i = 0; i < count; i++) { 280*1680d7b6SStephen Warren if (!fdtdec_get_is_enabled(fdt, nodes[i])) 281*1680d7b6SStephen Warren continue; 282*1680d7b6SStephen Warren 283*1680d7b6SStephen Warren padctl.socdata = socdata; 284*1680d7b6SStephen Warren 285*1680d7b6SStephen Warren err = tegra_xusb_padctl_parse_dt(&padctl, fdt, nodes[i]); 286*1680d7b6SStephen Warren if (err < 0) { 287*1680d7b6SStephen Warren error("failed to parse DT: %d", err); 288*1680d7b6SStephen Warren continue; 289*1680d7b6SStephen Warren } 290*1680d7b6SStephen Warren 291*1680d7b6SStephen Warren /* deassert XUSB padctl reset */ 292*1680d7b6SStephen Warren reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0); 293*1680d7b6SStephen Warren 294*1680d7b6SStephen Warren err = tegra_xusb_padctl_config_apply(&padctl, &padctl.config); 295*1680d7b6SStephen Warren if (err < 0) { 296*1680d7b6SStephen Warren error("failed to apply pinmux: %d", err); 297*1680d7b6SStephen Warren continue; 298*1680d7b6SStephen Warren } 299*1680d7b6SStephen Warren 300*1680d7b6SStephen Warren /* only a single instance is supported */ 301*1680d7b6SStephen Warren break; 302*1680d7b6SStephen Warren } 303*1680d7b6SStephen Warren 304*1680d7b6SStephen Warren return 0; 305*1680d7b6SStephen Warren } 306