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
20int __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
124out:
125	iounmap(usb_regs);
126	of_node_put(np);
127	return ret;
128}
129