xref: /OK3568_Linux_fs/u-boot/drivers/usb/common/fsl-dt-fixup.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2009, 2011 Freescale Semiconductor, Inc.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Author: Tor Krill tor@excito.com
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <usb.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun #include <hwconfig.h>
15*4882a593Smuzhiyun #include <fsl_errata.h>
16*4882a593Smuzhiyun #include <fsl_usb.h>
17*4882a593Smuzhiyun #include <fdt_support.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #ifndef CONFIG_USB_MAX_CONTROLLER_COUNT
20*4882a593Smuzhiyun #define CONFIG_USB_MAX_CONTROLLER_COUNT 1
21*4882a593Smuzhiyun #endif
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* USB Controllers */
24*4882a593Smuzhiyun #define FSL_USB2_MPH	"fsl-usb2-mph"
25*4882a593Smuzhiyun #define FSL_USB2_DR	"fsl-usb2-dr"
26*4882a593Smuzhiyun #define CHIPIDEA_USB2	"chipidea,usb2"
27*4882a593Smuzhiyun #define SNPS_DWC3	"snps,dwc3"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun static const char * const compat_usb_fsl[] = {
30*4882a593Smuzhiyun 	FSL_USB2_MPH,
31*4882a593Smuzhiyun 	FSL_USB2_DR,
32*4882a593Smuzhiyun 	SNPS_DWC3,
33*4882a593Smuzhiyun 	NULL
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun 
fdt_usb_get_node_type(void * blob,int start_offset,int * node_offset,const char ** node_type)36*4882a593Smuzhiyun static int fdt_usb_get_node_type(void *blob, int start_offset,
37*4882a593Smuzhiyun 				 int *node_offset, const char **node_type)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	int i;
40*4882a593Smuzhiyun 	int ret = -ENOENT;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	for (i = 0; compat_usb_fsl[i]; i++) {
43*4882a593Smuzhiyun 		*node_offset = fdt_node_offset_by_compatible
44*4882a593Smuzhiyun 					(blob, start_offset,
45*4882a593Smuzhiyun 					 compat_usb_fsl[i]);
46*4882a593Smuzhiyun 		if (*node_offset >= 0) {
47*4882a593Smuzhiyun 			*node_type = compat_usb_fsl[i];
48*4882a593Smuzhiyun 			ret = 0;
49*4882a593Smuzhiyun 			break;
50*4882a593Smuzhiyun 		}
51*4882a593Smuzhiyun 	}
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	return ret;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
fdt_fixup_usb_mode_phy_type(void * blob,const char * mode,const char * phy_type,int start_offset)56*4882a593Smuzhiyun static int fdt_fixup_usb_mode_phy_type(void *blob, const char *mode,
57*4882a593Smuzhiyun 				       const char *phy_type, int start_offset)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	const char *prop_mode = "dr_mode";
60*4882a593Smuzhiyun 	const char *prop_type = "phy_type";
61*4882a593Smuzhiyun 	const char *node_type = NULL;
62*4882a593Smuzhiyun 	int node_offset;
63*4882a593Smuzhiyun 	int err;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	err = fdt_usb_get_node_type(blob, start_offset,
66*4882a593Smuzhiyun 				    &node_offset, &node_type);
67*4882a593Smuzhiyun 	if (err < 0)
68*4882a593Smuzhiyun 		return err;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	if (mode) {
71*4882a593Smuzhiyun 		err = fdt_setprop(blob, node_offset, prop_mode, mode,
72*4882a593Smuzhiyun 				  strlen(mode) + 1);
73*4882a593Smuzhiyun 		if (err < 0)
74*4882a593Smuzhiyun 			printf("WARNING: could not set %s for %s: %s.\n",
75*4882a593Smuzhiyun 			       prop_mode, node_type, fdt_strerror(err));
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	if (phy_type) {
79*4882a593Smuzhiyun 		err = fdt_setprop(blob, node_offset, prop_type, phy_type,
80*4882a593Smuzhiyun 				  strlen(phy_type) + 1);
81*4882a593Smuzhiyun 		if (err < 0)
82*4882a593Smuzhiyun 			printf("WARNING: could not set %s for %s: %s.\n",
83*4882a593Smuzhiyun 			       prop_type, node_type, fdt_strerror(err));
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	return node_offset;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
fsl_fdt_fixup_usb_erratum(void * blob,const char * prop_erratum,const char * controller_type,int start_offset)89*4882a593Smuzhiyun static int fsl_fdt_fixup_usb_erratum(void *blob, const char *prop_erratum,
90*4882a593Smuzhiyun 				     const char *controller_type,
91*4882a593Smuzhiyun 				     int start_offset)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	int node_offset, err;
94*4882a593Smuzhiyun 	const char *node_type = NULL;
95*4882a593Smuzhiyun 	const char *node_name = NULL;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	err = fdt_usb_get_node_type(blob, start_offset,
98*4882a593Smuzhiyun 				    &node_offset, &node_type);
99*4882a593Smuzhiyun 	if (err < 0)
100*4882a593Smuzhiyun 		return err;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (!strcmp(node_type, FSL_USB2_MPH) || !strcmp(node_type, FSL_USB2_DR))
103*4882a593Smuzhiyun 		node_name = CHIPIDEA_USB2;
104*4882a593Smuzhiyun 	else
105*4882a593Smuzhiyun 		node_name = node_type;
106*4882a593Smuzhiyun 	if (strcmp(node_name, controller_type))
107*4882a593Smuzhiyun 		return err;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	err = fdt_setprop(blob, node_offset, prop_erratum, NULL, 0);
110*4882a593Smuzhiyun 	if (err < 0) {
111*4882a593Smuzhiyun 		printf("ERROR: could not set %s for %s: %s.\n",
112*4882a593Smuzhiyun 		       prop_erratum, node_type, fdt_strerror(err));
113*4882a593Smuzhiyun 	}
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return node_offset;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
fsl_fdt_fixup_erratum(int * usb_erratum_off,void * blob,const char * controller_type,char * str,bool (* has_erratum)(void))118*4882a593Smuzhiyun static int fsl_fdt_fixup_erratum(int *usb_erratum_off, void *blob,
119*4882a593Smuzhiyun 				 const char *controller_type, char *str,
120*4882a593Smuzhiyun 				 bool (*has_erratum)(void))
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	char buf[32] = {0};
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	snprintf(buf, sizeof(buf), "fsl,usb-erratum-%s", str);
125*4882a593Smuzhiyun 	if (!has_erratum())
126*4882a593Smuzhiyun 		return -EINVAL;
127*4882a593Smuzhiyun 	*usb_erratum_off = fsl_fdt_fixup_usb_erratum(blob, buf, controller_type,
128*4882a593Smuzhiyun 						     *usb_erratum_off);
129*4882a593Smuzhiyun 	if (*usb_erratum_off < 0)
130*4882a593Smuzhiyun 		return -ENOSPC;
131*4882a593Smuzhiyun 	debug("Adding USB erratum %s\n", str);
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
fsl_fdt_fixup_dr_usb(void * blob,bd_t * bd)135*4882a593Smuzhiyun void fsl_fdt_fixup_dr_usb(void *blob, bd_t *bd)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	static const char * const modes[] = { "host", "peripheral", "otg" };
138*4882a593Smuzhiyun 	static const char * const phys[] = { "ulpi", "utmi", "utmi_dual" };
139*4882a593Smuzhiyun 	int usb_erratum_a006261_off = -1;
140*4882a593Smuzhiyun 	int usb_erratum_a007075_off = -1;
141*4882a593Smuzhiyun 	int usb_erratum_a007792_off = -1;
142*4882a593Smuzhiyun 	int usb_erratum_a005697_off = -1;
143*4882a593Smuzhiyun 	int usb_erratum_a008751_off = -1;
144*4882a593Smuzhiyun 	int usb_mode_off = -1;
145*4882a593Smuzhiyun 	int usb_phy_off = -1;
146*4882a593Smuzhiyun 	char str[5];
147*4882a593Smuzhiyun 	int i, j;
148*4882a593Smuzhiyun 	int ret;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	for (i = 1; i <= CONFIG_USB_MAX_CONTROLLER_COUNT; i++) {
151*4882a593Smuzhiyun 		const char *dr_mode_type = NULL;
152*4882a593Smuzhiyun 		const char *dr_phy_type = NULL;
153*4882a593Smuzhiyun 		int mode_idx = -1, phy_idx = -1;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		snprintf(str, 5, "%s%d", "usb", i);
156*4882a593Smuzhiyun 		if (hwconfig(str)) {
157*4882a593Smuzhiyun 			for (j = 0; j < ARRAY_SIZE(modes); j++) {
158*4882a593Smuzhiyun 				if (hwconfig_subarg_cmp(str, "dr_mode",
159*4882a593Smuzhiyun 							modes[j])) {
160*4882a593Smuzhiyun 					mode_idx = j;
161*4882a593Smuzhiyun 					break;
162*4882a593Smuzhiyun 				}
163*4882a593Smuzhiyun 			}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 			for (j = 0; j < ARRAY_SIZE(phys); j++) {
166*4882a593Smuzhiyun 				if (hwconfig_subarg_cmp(str, "phy_type",
167*4882a593Smuzhiyun 							phys[j])) {
168*4882a593Smuzhiyun 					phy_idx = j;
169*4882a593Smuzhiyun 					break;
170*4882a593Smuzhiyun 				}
171*4882a593Smuzhiyun 			}
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 			if (mode_idx < 0 && phy_idx < 0) {
174*4882a593Smuzhiyun 				printf("WARNING: invalid phy or mode\n");
175*4882a593Smuzhiyun 				return;
176*4882a593Smuzhiyun 			}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 			if (mode_idx > -1)
179*4882a593Smuzhiyun 				dr_mode_type = modes[mode_idx];
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 			if (phy_idx > -1)
182*4882a593Smuzhiyun 				dr_phy_type = phys[phy_idx];
183*4882a593Smuzhiyun 		}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 		if (has_dual_phy())
186*4882a593Smuzhiyun 			dr_phy_type = phys[2];
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 		usb_mode_off = fdt_fixup_usb_mode_phy_type(blob,
189*4882a593Smuzhiyun 							   dr_mode_type, NULL,
190*4882a593Smuzhiyun 							   usb_mode_off);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		if (usb_mode_off < 0)
193*4882a593Smuzhiyun 			return;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		usb_phy_off = fdt_fixup_usb_mode_phy_type(blob,
196*4882a593Smuzhiyun 							  NULL, dr_phy_type,
197*4882a593Smuzhiyun 							  usb_phy_off);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 		if (usb_phy_off < 0)
200*4882a593Smuzhiyun 			return;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 		ret = fsl_fdt_fixup_erratum(&usb_erratum_a006261_off, blob,
203*4882a593Smuzhiyun 					    CHIPIDEA_USB2, "a006261",
204*4882a593Smuzhiyun 					    has_erratum_a006261);
205*4882a593Smuzhiyun 		if (ret == -ENOSPC)
206*4882a593Smuzhiyun 			return;
207*4882a593Smuzhiyun 		ret = fsl_fdt_fixup_erratum(&usb_erratum_a007075_off, blob,
208*4882a593Smuzhiyun 					    CHIPIDEA_USB2, "a007075",
209*4882a593Smuzhiyun 					    has_erratum_a007075);
210*4882a593Smuzhiyun 		if (ret == -ENOSPC)
211*4882a593Smuzhiyun 			return;
212*4882a593Smuzhiyun 		ret = fsl_fdt_fixup_erratum(&usb_erratum_a007792_off, blob,
213*4882a593Smuzhiyun 					    CHIPIDEA_USB2, "a007792",
214*4882a593Smuzhiyun 					    has_erratum_a007792);
215*4882a593Smuzhiyun 		if (ret == -ENOSPC)
216*4882a593Smuzhiyun 			return;
217*4882a593Smuzhiyun 		ret = fsl_fdt_fixup_erratum(&usb_erratum_a005697_off, blob,
218*4882a593Smuzhiyun 					    CHIPIDEA_USB2, "a005697",
219*4882a593Smuzhiyun 					    has_erratum_a005697);
220*4882a593Smuzhiyun 		if (ret == -ENOSPC)
221*4882a593Smuzhiyun 			return;
222*4882a593Smuzhiyun 		ret = fsl_fdt_fixup_erratum(&usb_erratum_a008751_off, blob,
223*4882a593Smuzhiyun 					    SNPS_DWC3, "a008751",
224*4882a593Smuzhiyun 					    has_erratum_a008751);
225*4882a593Smuzhiyun 		if (ret == -ENOSPC)
226*4882a593Smuzhiyun 			return;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun }
230