xref: /rk3399_rockchip-uboot/arch/arm/mach-tegra/xusb-padctl-common.c (revision 90aa625c9a9e1fb7a2f001fd8e50099bacaf92b8)
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 
tegra_xusb_phy_prepare(struct tegra_xusb_phy * phy)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 
tegra_xusb_phy_enable(struct tegra_xusb_phy * phy)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 
tegra_xusb_phy_disable(struct tegra_xusb_phy * phy)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 
tegra_xusb_phy_unprepare(struct tegra_xusb_phy * phy)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 
tegra_xusb_phy_get(unsigned int type)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 *
tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl * padctl,const char * name)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
tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl * padctl,struct tegra_xusb_padctl_group * group,ofnode node)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) {
87*90aa625cSMasahiro Yamada 		pr_err("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) {
97*90aa625cSMasahiro Yamada 			pr_err("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) {
107*90aa625cSMasahiro Yamada 		pr_err("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 
tegra_xusb_padctl_find_function(struct tegra_xusb_padctl * padctl,const char * name)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
tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl * padctl,const struct tegra_xusb_padctl_lane * lane,const char * name)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
tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl * padctl,const struct tegra_xusb_padctl_group * group)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) {
160*90aa625cSMasahiro Yamada 			pr_err("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) {
167*90aa625cSMasahiro Yamada 			pr_err("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
tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl * padctl,struct tegra_xusb_padctl_config * config)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) {
209*90aa625cSMasahiro Yamada 			pr_err("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
tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl * padctl,struct tegra_xusb_padctl_config * config,ofnode node)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 
22717c82fdcSSimon 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) {
235*90aa625cSMasahiro Yamada 			pr_err("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 
tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl * padctl,ofnode node)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) {
253*90aa625cSMasahiro Yamada 		pr_err("registers not found");
2541680d7b6SStephen Warren 		return err;
2551680d7b6SStephen Warren 	}
2561680d7b6SStephen Warren 
25717c82fdcSSimon 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) {
264*90aa625cSMasahiro Yamada 			pr_err("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 
tegra_xusb_process_nodes(ofnode nodes[],unsigned int count,const struct tegra_xusb_padctl_soc * socdata)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) {
292*90aa625cSMasahiro Yamada 			pr_err("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) {
301*90aa625cSMasahiro Yamada 			pr_err("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