blob: 28fdebe50a331c173cd6b7f196cb9aedd501a479 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0
Stephen Warren1680d7b2015-10-23 10:50:49 -06002/*
3 * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
Stephen Warren1680d7b2015-10-23 10:50:49 -06004 */
5
6#define pr_fmt(fmt) "tegra-xusb-padctl: " fmt
7
8#include <common.h>
9#include <errno.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Simon Glass1e94b462023-09-14 18:21:46 -060011#include <linux/printk.h>
Stephen Warren1680d7b2015-10-23 10:50:49 -060012
13#include "xusb-padctl-common.h"
14
15#include <asm/arch/clock.h>
16
17int tegra_xusb_phy_prepare(struct tegra_xusb_phy *phy)
18{
19 if (phy && phy->ops && phy->ops->prepare)
20 return phy->ops->prepare(phy);
21
22 return phy ? -ENOSYS : -EINVAL;
23}
24
25int tegra_xusb_phy_enable(struct tegra_xusb_phy *phy)
26{
27 if (phy && phy->ops && phy->ops->enable)
28 return phy->ops->enable(phy);
29
30 return phy ? -ENOSYS : -EINVAL;
31}
32
33int tegra_xusb_phy_disable(struct tegra_xusb_phy *phy)
34{
35 if (phy && phy->ops && phy->ops->disable)
36 return phy->ops->disable(phy);
37
38 return phy ? -ENOSYS : -EINVAL;
39}
40
41int tegra_xusb_phy_unprepare(struct tegra_xusb_phy *phy)
42{
43 if (phy && phy->ops && phy->ops->unprepare)
44 return phy->ops->unprepare(phy);
45
46 return phy ? -ENOSYS : -EINVAL;
47}
48
49struct tegra_xusb_phy *tegra_xusb_phy_get(unsigned int type)
50{
51 struct tegra_xusb_phy *phy;
52 int i;
53
54 for (i = 0; i < padctl.socdata->num_phys; i++) {
55 phy = &padctl.socdata->phys[i];
56 if (phy->type != type)
57 continue;
58 return phy;
59 }
60
61 return NULL;
62}
63
64static const struct tegra_xusb_padctl_lane *
65tegra_xusb_padctl_find_lane(struct tegra_xusb_padctl *padctl, const char *name)
66{
67 unsigned int i;
68
69 for (i = 0; i < padctl->socdata->num_lanes; i++)
70 if (strcmp(name, padctl->socdata->lanes[i].name) == 0)
71 return &padctl->socdata->lanes[i];
72
73 return NULL;
74}
75
76static int
77tegra_xusb_padctl_group_parse_dt(struct tegra_xusb_padctl *padctl,
78 struct tegra_xusb_padctl_group *group,
Simon Glassbe789092017-07-25 08:29:59 -060079 ofnode node)
Stephen Warren1680d7b2015-10-23 10:50:49 -060080{
81 unsigned int i;
Simon Glassbe789092017-07-25 08:29:59 -060082 int len, ret;
Stephen Warren1680d7b2015-10-23 10:50:49 -060083
Simon Glassbe789092017-07-25 08:29:59 -060084 group->name = ofnode_get_name(node);
Stephen Warren1680d7b2015-10-23 10:50:49 -060085
Simon Glassbe789092017-07-25 08:29:59 -060086 len = ofnode_read_string_count(node, "nvidia,lanes");
Stephen Warren1680d7b2015-10-23 10:50:49 -060087 if (len < 0) {
Peter Robinson5b060e42022-05-03 09:29:21 +010088 pr_err("failed to parse \"nvidia,lanes\" property\n");
Stephen Warren1680d7b2015-10-23 10:50:49 -060089 return -EINVAL;
90 }
91
92 group->num_pins = len;
93
94 for (i = 0; i < group->num_pins; i++) {
Simon Glassbe789092017-07-25 08:29:59 -060095 ret = ofnode_read_string_index(node, "nvidia,lanes", i,
96 &group->pins[i]);
97 if (ret) {
Peter Robinson5b060e42022-05-03 09:29:21 +010098 pr_err("failed to read string from \"nvidia,lanes\" property\n");
Stephen Warren1680d7b2015-10-23 10:50:49 -060099 return -EINVAL;
100 }
101 }
102
103 group->num_pins = len;
104
Simon Glassbe789092017-07-25 08:29:59 -0600105 ret = ofnode_read_string_index(node, "nvidia,function", 0,
106 &group->func);
107 if (ret) {
Peter Robinson5b060e42022-05-03 09:29:21 +0100108 pr_err("failed to parse \"nvidia,func\" property\n");
Stephen Warren1680d7b2015-10-23 10:50:49 -0600109 return -EINVAL;
110 }
111
Simon Glassbe789092017-07-25 08:29:59 -0600112 group->iddq = ofnode_read_u32_default(node, "nvidia,iddq", -1);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600113
114 return 0;
115}
116
117static int tegra_xusb_padctl_find_function(struct tegra_xusb_padctl *padctl,
118 const char *name)
119{
120 unsigned int i;
121
122 for (i = 0; i < padctl->socdata->num_functions; i++)
123 if (strcmp(name, padctl->socdata->functions[i]) == 0)
124 return i;
125
126 return -ENOENT;
127}
128
129static int
130tegra_xusb_padctl_lane_find_function(struct tegra_xusb_padctl *padctl,
131 const struct tegra_xusb_padctl_lane *lane,
132 const char *name)
133{
134 unsigned int i;
135 int func;
136
137 func = tegra_xusb_padctl_find_function(padctl, name);
138 if (func < 0)
139 return func;
140
141 for (i = 0; i < lane->num_funcs; i++)
142 if (lane->funcs[i] == func)
143 return i;
144
145 return -ENOENT;
146}
147
148static int
149tegra_xusb_padctl_group_apply(struct tegra_xusb_padctl *padctl,
150 const struct tegra_xusb_padctl_group *group)
151{
152 unsigned int i;
153
154 for (i = 0; i < group->num_pins; i++) {
155 const struct tegra_xusb_padctl_lane *lane;
156 unsigned int func;
157 u32 value;
158
159 lane = tegra_xusb_padctl_find_lane(padctl, group->pins[i]);
160 if (!lane) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900161 pr_err("no lane for pin %s", group->pins[i]);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600162 continue;
163 }
164
165 func = tegra_xusb_padctl_lane_find_function(padctl, lane,
166 group->func);
167 if (func < 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900168 pr_err("function %s invalid for lane %s: %d",
Stephen Warren1680d7b2015-10-23 10:50:49 -0600169 group->func, lane->name, func);
170 continue;
171 }
172
173 value = padctl_readl(padctl, lane->offset);
174
175 /* set pin function */
176 value &= ~(lane->mask << lane->shift);
177 value |= func << lane->shift;
178
179 /*
180 * Set IDDQ if supported on the lane and specified in the
181 * configuration.
182 */
183 if (lane->iddq > 0 && group->iddq >= 0) {
184 if (group->iddq != 0)
185 value &= ~(1 << lane->iddq);
186 else
187 value |= 1 << lane->iddq;
188 }
189
190 padctl_writel(padctl, value, lane->offset);
191 }
192
193 return 0;
194}
195
196static int
197tegra_xusb_padctl_config_apply(struct tegra_xusb_padctl *padctl,
198 struct tegra_xusb_padctl_config *config)
199{
200 unsigned int i;
201
202 for (i = 0; i < config->num_groups; i++) {
203 const struct tegra_xusb_padctl_group *group;
204 int err;
205
206 group = &config->groups[i];
207
208 err = tegra_xusb_padctl_group_apply(padctl, group);
209 if (err < 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900210 pr_err("failed to apply group %s: %d",
Stephen Warren1680d7b2015-10-23 10:50:49 -0600211 group->name, err);
212 continue;
213 }
214 }
215
216 return 0;
217}
218
219static int
220tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl,
221 struct tegra_xusb_padctl_config *config,
Simon Glassbe789092017-07-25 08:29:59 -0600222 ofnode node)
Stephen Warren1680d7b2015-10-23 10:50:49 -0600223{
Simon Glassbe789092017-07-25 08:29:59 -0600224 ofnode subnode;
Stephen Warren1680d7b2015-10-23 10:50:49 -0600225
Simon Glassbe789092017-07-25 08:29:59 -0600226 config->name = ofnode_get_name(node);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600227
Simon Glass3991f422017-08-05 15:45:54 -0600228 ofnode_for_each_subnode(subnode, node) {
Stephen Warren1680d7b2015-10-23 10:50:49 -0600229 struct tegra_xusb_padctl_group *group;
230 int err;
231
232 group = &config->groups[config->num_groups];
233
Simon Glassbe789092017-07-25 08:29:59 -0600234 err = tegra_xusb_padctl_group_parse_dt(padctl, group, subnode);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600235 if (err < 0) {
Peter Robinson5b060e42022-05-03 09:29:21 +0100236 pr_err("failed to parse group %s\n", group->name);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600237 return err;
238 }
239
240 config->num_groups++;
241 }
242
243 return 0;
244}
245
246static int tegra_xusb_padctl_parse_dt(struct tegra_xusb_padctl *padctl,
Simon Glassbe789092017-07-25 08:29:59 -0600247 ofnode node)
Stephen Warren1680d7b2015-10-23 10:50:49 -0600248{
Simon Glassbe789092017-07-25 08:29:59 -0600249 ofnode subnode;
250 int err;
Stephen Warren1680d7b2015-10-23 10:50:49 -0600251
Simon Glassbe789092017-07-25 08:29:59 -0600252 err = ofnode_read_resource(node, 0, &padctl->regs);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600253 if (err < 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900254 pr_err("registers not found");
Stephen Warren1680d7b2015-10-23 10:50:49 -0600255 return err;
256 }
257
Simon Glass3991f422017-08-05 15:45:54 -0600258 ofnode_for_each_subnode(subnode, node) {
Stephen Warren1680d7b2015-10-23 10:50:49 -0600259 struct tegra_xusb_padctl_config *config = &padctl->config;
260
Simon Glassbe789092017-07-25 08:29:59 -0600261 debug("%s: subnode=%s\n", __func__, ofnode_get_name(subnode));
262 err = tegra_xusb_padctl_config_parse_dt(padctl, config,
Stephen Warren1680d7b2015-10-23 10:50:49 -0600263 subnode);
264 if (err < 0) {
Peter Robinson5b060e42022-05-03 09:29:21 +0100265 pr_err("failed to parse entry %s: %d\n",
Stephen Warren1680d7b2015-10-23 10:50:49 -0600266 config->name, err);
267 continue;
268 }
269 }
Simon Glassbe789092017-07-25 08:29:59 -0600270 debug("%s: done\n", __func__);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600271
272 return 0;
273}
274
275struct tegra_xusb_padctl padctl;
276
Simon Glassbe789092017-07-25 08:29:59 -0600277int tegra_xusb_process_nodes(ofnode nodes[], unsigned int count,
278 const struct tegra_xusb_padctl_soc *socdata)
Stephen Warren1680d7b2015-10-23 10:50:49 -0600279{
280 unsigned int i;
281 int err;
282
Simon Glassbe789092017-07-25 08:29:59 -0600283 debug("%s: count=%d\n", __func__, count);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600284 for (i = 0; i < count; i++) {
Simon Glassbe789092017-07-25 08:29:59 -0600285 debug("%s: i=%d, node=%p\n", __func__, i, nodes[i].np);
Simon Glass89090662022-09-06 20:27:17 -0600286 if (!ofnode_is_enabled(nodes[i]))
Stephen Warren1680d7b2015-10-23 10:50:49 -0600287 continue;
288
289 padctl.socdata = socdata;
290
Simon Glassbe789092017-07-25 08:29:59 -0600291 err = tegra_xusb_padctl_parse_dt(&padctl, nodes[i]);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600292 if (err < 0) {
Peter Robinson5b060e42022-05-03 09:29:21 +0100293 pr_err("failed to parse DT: %d\n", err);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600294 continue;
295 }
296
297 /* deassert XUSB padctl reset */
298 reset_set_enable(PERIPH_ID_XUSB_PADCTL, 0);
299
300 err = tegra_xusb_padctl_config_apply(&padctl, &padctl.config);
301 if (err < 0) {
Masahiro Yamada9b643e32017-09-16 14:10:41 +0900302 pr_err("failed to apply pinmux: %d", err);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600303 continue;
304 }
305
306 /* only a single instance is supported */
307 break;
308 }
Simon Glassbe789092017-07-25 08:29:59 -0600309 debug("%s: done\n", __func__);
Stephen Warren1680d7b2015-10-23 10:50:49 -0600310
311 return 0;
312}