blob: 6a68bd76c2742c89862c82a4106bf9b9c4db6c03 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Sriram Dash55f01cc2016-04-05 14:41:19 +05302/*
3 * (C) Copyright 2009, 2011 Freescale Semiconductor, Inc.
4 *
5 * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
6 *
7 * Author: Tor Krill tor@excito.com
Sriram Dash55f01cc2016-04-05 14:41:19 +05308 */
9
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Sriram Dash55f01cc2016-04-05 14:41:19 +053011#include <usb.h>
12#include <asm/io.h>
13#include <hwconfig.h>
Sriram Dash9e8da5c2016-06-13 09:58:34 +053014#include <fsl_errata.h>
Sriram Dash55f01cc2016-04-05 14:41:19 +053015#include <fsl_usb.h>
16#include <fdt_support.h>
17
Sriram Dasheacf09c2016-06-13 09:58:33 +053018/* USB Controllers */
19#define FSL_USB2_MPH "fsl-usb2-mph"
20#define FSL_USB2_DR "fsl-usb2-dr"
21#define CHIPIDEA_USB2 "chipidea,usb2"
22#define SNPS_DWC3 "snps,dwc3"
23
Sriram Dash2510ff52016-04-05 14:41:21 +053024static const char * const compat_usb_fsl[] = {
Sriram Dasheacf09c2016-06-13 09:58:33 +053025 FSL_USB2_MPH,
26 FSL_USB2_DR,
27 SNPS_DWC3,
Sriram Dash2510ff52016-04-05 14:41:21 +053028 NULL
29};
30
Sriram Dashc0a7fe22016-04-05 14:41:22 +053031static int fdt_usb_get_node_type(void *blob, int start_offset,
32 int *node_offset, const char **node_type)
Sriram Dash55f01cc2016-04-05 14:41:19 +053033{
Sriram Dash2510ff52016-04-05 14:41:21 +053034 int i;
Sriram Dashc0a7fe22016-04-05 14:41:22 +053035 int ret = -ENOENT;
Sriram Dash55f01cc2016-04-05 14:41:19 +053036
Sriram Dash2510ff52016-04-05 14:41:21 +053037 for (i = 0; compat_usb_fsl[i]; i++) {
38 *node_offset = fdt_node_offset_by_compatible
39 (blob, start_offset,
40 compat_usb_fsl[i]);
41 if (*node_offset >= 0) {
Sriram Dashc0a7fe22016-04-05 14:41:22 +053042 *node_type = compat_usb_fsl[i];
43 ret = 0;
Sriram Dash2510ff52016-04-05 14:41:21 +053044 break;
Sriram Dash55f01cc2016-04-05 14:41:19 +053045 }
Sriram Dash55f01cc2016-04-05 14:41:19 +053046 }
47
Sriram Dashc0a7fe22016-04-05 14:41:22 +053048 return ret;
Sriram Dash70c08152016-04-05 14:41:20 +053049}
50
51static int fdt_fixup_usb_mode_phy_type(void *blob, const char *mode,
52 const char *phy_type, int start_offset)
53{
54 const char *prop_mode = "dr_mode";
55 const char *prop_type = "phy_type";
56 const char *node_type = NULL;
57 int node_offset;
58 int err;
59
Sriram Dashc0a7fe22016-04-05 14:41:22 +053060 err = fdt_usb_get_node_type(blob, start_offset,
61 &node_offset, &node_type);
62 if (err < 0)
63 return err;
Sriram Dash70c08152016-04-05 14:41:20 +053064
Sriram Dash55f01cc2016-04-05 14:41:19 +053065 if (mode) {
66 err = fdt_setprop(blob, node_offset, prop_mode, mode,
67 strlen(mode) + 1);
68 if (err < 0)
69 printf("WARNING: could not set %s for %s: %s.\n",
70 prop_mode, node_type, fdt_strerror(err));
71 }
72
73 if (phy_type) {
74 err = fdt_setprop(blob, node_offset, prop_type, phy_type,
75 strlen(phy_type) + 1);
76 if (err < 0)
77 printf("WARNING: could not set %s for %s: %s.\n",
78 prop_type, node_type, fdt_strerror(err));
79 }
80
81 return node_offset;
82}
83
Sriram Dasha3c1f692016-09-16 17:12:16 +053084static int fsl_fdt_fixup_usb_erratum(void *blob, const char *prop_erratum,
85 const char *controller_type,
86 int start_offset)
Sriram Dash55f01cc2016-04-05 14:41:19 +053087{
88 int node_offset, err;
89 const char *node_type = NULL;
Sriram Dasheacf09c2016-06-13 09:58:33 +053090 const char *node_name = NULL;
Sriram Dash55f01cc2016-04-05 14:41:19 +053091
Sriram Dashc0a7fe22016-04-05 14:41:22 +053092 err = fdt_usb_get_node_type(blob, start_offset,
93 &node_offset, &node_type);
94 if (err < 0)
95 return err;
Sriram Dash55f01cc2016-04-05 14:41:19 +053096
Sriram Dasheacf09c2016-06-13 09:58:33 +053097 if (!strcmp(node_type, FSL_USB2_MPH) || !strcmp(node_type, FSL_USB2_DR))
98 node_name = CHIPIDEA_USB2;
99 else
100 node_name = node_type;
101 if (strcmp(node_name, controller_type))
102 return err;
103
Sriram Dash55f01cc2016-04-05 14:41:19 +0530104 err = fdt_setprop(blob, node_offset, prop_erratum, NULL, 0);
105 if (err < 0) {
106 printf("ERROR: could not set %s for %s: %s.\n",
107 prop_erratum, node_type, fdt_strerror(err));
108 }
109
110 return node_offset;
111}
112
Sriram Dasha3c1f692016-09-16 17:12:16 +0530113static int fsl_fdt_fixup_erratum(int *usb_erratum_off, void *blob,
114 const char *controller_type, char *str,
115 bool (*has_erratum)(void))
Sriram Dasheacf09c2016-06-13 09:58:33 +0530116{
117 char buf[32] = {0};
118
119 snprintf(buf, sizeof(buf), "fsl,usb-erratum-%s", str);
120 if (!has_erratum())
121 return -EINVAL;
Sriram Dasha3c1f692016-09-16 17:12:16 +0530122 *usb_erratum_off = fsl_fdt_fixup_usb_erratum(blob, buf, controller_type,
123 *usb_erratum_off);
Sriram Dasheacf09c2016-06-13 09:58:33 +0530124 if (*usb_erratum_off < 0)
125 return -ENOSPC;
126 debug("Adding USB erratum %s\n", str);
127 return 0;
128}
129
Masahiro Yamadaf7ed78b2020-06-26 15:13:33 +0900130void fsl_fdt_fixup_dr_usb(void *blob, struct bd_info *bd)
Sriram Dash55f01cc2016-04-05 14:41:19 +0530131{
132 static const char * const modes[] = { "host", "peripheral", "otg" };
133 static const char * const phys[] = { "ulpi", "utmi", "utmi_dual" };
134 int usb_erratum_a006261_off = -1;
135 int usb_erratum_a007075_off = -1;
136 int usb_erratum_a007792_off = -1;
137 int usb_erratum_a005697_off = -1;
Sriram Dash01820952016-06-13 09:58:36 +0530138 int usb_erratum_a008751_off = -1;
Sriram Dash55f01cc2016-04-05 14:41:19 +0530139 int usb_mode_off = -1;
140 int usb_phy_off = -1;
141 char str[5];
142 int i, j;
Sriram Dasheacf09c2016-06-13 09:58:33 +0530143 int ret;
Sriram Dash55f01cc2016-04-05 14:41:19 +0530144
145 for (i = 1; i <= CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
146 const char *dr_mode_type = NULL;
147 const char *dr_phy_type = NULL;
148 int mode_idx = -1, phy_idx = -1;
149
150 snprintf(str, 5, "%s%d", "usb", i);
151 if (hwconfig(str)) {
152 for (j = 0; j < ARRAY_SIZE(modes); j++) {
153 if (hwconfig_subarg_cmp(str, "dr_mode",
154 modes[j])) {
155 mode_idx = j;
156 break;
157 }
158 }
159
160 for (j = 0; j < ARRAY_SIZE(phys); j++) {
161 if (hwconfig_subarg_cmp(str, "phy_type",
162 phys[j])) {
163 phy_idx = j;
164 break;
165 }
166 }
167
168 if (mode_idx < 0 && phy_idx < 0) {
169 printf("WARNING: invalid phy or mode\n");
170 return;
171 }
172
173 if (mode_idx > -1)
174 dr_mode_type = modes[mode_idx];
175
176 if (phy_idx > -1)
177 dr_phy_type = phys[phy_idx];
178 }
179
180 if (has_dual_phy())
181 dr_phy_type = phys[2];
182
183 usb_mode_off = fdt_fixup_usb_mode_phy_type(blob,
184 dr_mode_type, NULL,
185 usb_mode_off);
186
187 if (usb_mode_off < 0)
188 return;
189
190 usb_phy_off = fdt_fixup_usb_mode_phy_type(blob,
191 NULL, dr_phy_type,
192 usb_phy_off);
193
194 if (usb_phy_off < 0)
195 return;
196
Sriram Dasha3c1f692016-09-16 17:12:16 +0530197 ret = fsl_fdt_fixup_erratum(&usb_erratum_a006261_off, blob,
198 CHIPIDEA_USB2, "a006261",
199 has_erratum_a006261);
Sriram Dasheacf09c2016-06-13 09:58:33 +0530200 if (ret == -ENOSPC)
201 return;
Sriram Dasha3c1f692016-09-16 17:12:16 +0530202 ret = fsl_fdt_fixup_erratum(&usb_erratum_a007075_off, blob,
203 CHIPIDEA_USB2, "a007075",
204 has_erratum_a007075);
Sriram Dasheacf09c2016-06-13 09:58:33 +0530205 if (ret == -ENOSPC)
206 return;
Sriram Dasha3c1f692016-09-16 17:12:16 +0530207 ret = fsl_fdt_fixup_erratum(&usb_erratum_a007792_off, blob,
208 CHIPIDEA_USB2, "a007792",
209 has_erratum_a007792);
Sriram Dasheacf09c2016-06-13 09:58:33 +0530210 if (ret == -ENOSPC)
211 return;
Sriram Dasha3c1f692016-09-16 17:12:16 +0530212 ret = fsl_fdt_fixup_erratum(&usb_erratum_a005697_off, blob,
213 CHIPIDEA_USB2, "a005697",
214 has_erratum_a005697);
Sriram Dasheacf09c2016-06-13 09:58:33 +0530215 if (ret == -ENOSPC)
216 return;
Sriram Dasha3c1f692016-09-16 17:12:16 +0530217 ret = fsl_fdt_fixup_erratum(&usb_erratum_a008751_off, blob,
218 SNPS_DWC3, "a008751",
219 has_erratum_a008751);
Sriram Dash01820952016-06-13 09:58:36 +0530220 if (ret == -ENOSPC)
221 return;
222
Sriram Dash55f01cc2016-04-05 14:41:19 +0530223 }
224}