1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Freescale 83xx USB SOC setup code
4  *
5  * Copyright (C) 2007 Freescale Semiconductor, Inc.
6  * Author: Li Yang
7  */
8 
9 #include <linux/stddef.h>
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/of.h>
13 #include <linux/of_address.h>
14 #include <linux/io.h>
15 
16 #include <sysdev/fsl_soc.h>
17 
18 #include "mpc83xx.h"
19 
20 int __init mpc831x_usb_cfg(void)
21 {
22 	u32 temp;
23 	void __iomem *immap, *usb_regs;
24 	struct device_node *np = NULL;
25 	struct device_node *immr_node = NULL;
26 	const void *prop;
27 	struct resource res;
28 	int ret = 0;
29 #ifdef CONFIG_USB_OTG
30 	const void *dr_mode;
31 #endif
32 
33 	np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr");
34 	if (!np)
35 		return -ENODEV;
36 	prop = of_get_property(np, "phy_type", NULL);
37 
38 	/* Map IMMR space for pin and clock settings */
39 	immap = ioremap(get_immrbase(), 0x1000);
40 	if (!immap) {
41 		of_node_put(np);
42 		return -ENOMEM;
43 	}
44 
45 	/* Configure clock */
46 	immr_node = of_get_parent(np);
47 	if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") ||
48 			  of_device_is_compatible(immr_node, "fsl,mpc8308-immr")))
49 		clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
50 				MPC8315_SCCR_USB_MASK,
51 				MPC8315_SCCR_USB_DRCM_01);
52 	else
53 		clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
54 				MPC83XX_SCCR_USB_MASK,
55 				MPC83XX_SCCR_USB_DRCM_11);
56 
57 	/* Configure pin mux for ULPI.  There is no pin mux for UTMI */
58 	if (prop && !strcmp(prop, "ulpi")) {
59 		if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
60 			clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
61 					MPC8308_SICRH_USB_MASK,
62 					MPC8308_SICRH_USB_ULPI);
63 		} else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
64 			clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
65 					MPC8315_SICRL_USB_MASK,
66 					MPC8315_SICRL_USB_ULPI);
67 			clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
68 					MPC8315_SICRH_USB_MASK,
69 					MPC8315_SICRH_USB_ULPI);
70 		} else {
71 			clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
72 					MPC831X_SICRL_USB_MASK,
73 					MPC831X_SICRL_USB_ULPI);
74 			clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
75 					MPC831X_SICRH_USB_MASK,
76 					MPC831X_SICRH_USB_ULPI);
77 		}
78 	}
79 
80 	iounmap(immap);
81 
82 	of_node_put(immr_node);
83 
84 	/* Map USB SOC space */
85 	ret = of_address_to_resource(np, 0, &res);
86 	if (ret) {
87 		of_node_put(np);
88 		return ret;
89 	}
90 	usb_regs = ioremap(res.start, resource_size(&res));
91 
92 	/* Using on-chip PHY */
93 	if (prop && (!strcmp(prop, "utmi_wide") || !strcmp(prop, "utmi"))) {
94 		u32 refsel;
95 
96 		if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))
97 			goto out;
98 
99 		if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
100 			refsel = CONTROL_REFSEL_24MHZ;
101 		else
102 			refsel = CONTROL_REFSEL_48MHZ;
103 		/* Set UTMI_PHY_EN and REFSEL */
104 		out_be32(usb_regs + FSL_USB2_CONTROL_OFFS,
105 			 CONTROL_UTMI_PHY_EN | refsel);
106 	/* Using external UPLI PHY */
107 	} else if (prop && !strcmp(prop, "ulpi")) {
108 		/* Set PHY_CLK_SEL to ULPI */
109 		temp = CONTROL_PHY_CLK_SEL_ULPI;
110 #ifdef CONFIG_USB_OTG
111 		/* Set OTG_PORT */
112 		if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
113 			dr_mode = of_get_property(np, "dr_mode", NULL);
114 			if (dr_mode && !strcmp(dr_mode, "otg"))
115 				temp |= CONTROL_OTG_PORT;
116 		}
117 #endif /* CONFIG_USB_OTG */
118 		out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp);
119 	} else {
120 		pr_warn("831x USB PHY type not supported\n");
121 		ret = -EINVAL;
122 	}
123 
124 out:
125 	iounmap(usb_regs);
126 	of_node_put(np);
127 	return ret;
128 }
129