1 // SPDX-License-Identifier: GPL-2.0
2 /**
3  * cdns_ti-ti.c - TI specific Glue layer for Cadence USB Controller
4  *
5  * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
6  */
7 
8 #include <common.h>
9 #include <asm-generic/io.h>
10 #include <clk.h>
11 #include <dm.h>
12 #include <dm/device_compat.h>
13 #include <linux/bitops.h>
14 #include <linux/io.h>
15 #include <linux/usb/otg.h>
16 #include <malloc.h>
17 
18 #include "core.h"
19 
20 /* USB Wrapper register offsets */
21 #define USBSS_PID		0x0
22 #define	USBSS_W1		0x4
23 #define USBSS_STATIC_CONFIG	0x8
24 #define USBSS_PHY_TEST		0xc
25 #define	USBSS_DEBUG_CTRL	0x10
26 #define	USBSS_DEBUG_INFO	0x14
27 #define	USBSS_DEBUG_LINK_STATE	0x18
28 #define	USBSS_DEVICE_CTRL	0x1c
29 
30 /* Wrapper 1 register bits */
31 #define USBSS_W1_PWRUP_RST		BIT(0)
32 #define USBSS_W1_OVERCURRENT_SEL	BIT(8)
33 #define USBSS_W1_MODESTRAP_SEL		BIT(9)
34 #define USBSS_W1_OVERCURRENT		BIT(16)
35 #define USBSS_W1_MODESTRAP_MASK		GENMASK(18, 17)
36 #define USBSS_W1_MODESTRAP_SHIFT	17
37 #define USBSS_W1_USB2_ONLY		BIT(19)
38 
39 /* Static config register bits */
40 #define USBSS1_STATIC_PLL_REF_SEL_MASK	GENMASK(8, 5)
41 #define USBSS1_STATIC_PLL_REF_SEL_SHIFT	5
42 #define USBSS1_STATIC_LOOPBACK_MODE_MASK	GENMASK(4, 3)
43 #define USBSS1_STATIC_LOOPBACK_MODE_SHIFT	3
44 #define USBSS1_STATIC_VBUS_SEL_MASK	GENMASK(2, 1)
45 #define USBSS1_STATIC_VBUS_SEL_SHIFT	1
46 #define USBSS1_STATIC_LANE_REVERSE	BIT(0)
47 
48 /* Modestrap modes */
49 enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
50 		      USBSS_MODESTRAP_MODE_HOST,
51 		      USBSS_MODESTRAP_MODE_PERIPHERAL};
52 
53 struct cdns_ti {
54 	struct udevice *dev;
55 	void __iomem *usbss;
56 	int usb2_only:1;
57 	int vbus_divider:1;
58 	struct clk *usb2_refclk;
59 	struct clk *lpm_clk;
60 };
61 
62 static const int cdns_ti_rate_table[] = {	/* in KHZ */
63 	9600,
64 	10000,
65 	12000,
66 	19200,
67 	20000,
68 	24000,
69 	25000,
70 	26000,
71 	38400,
72 	40000,
73 	58000,
74 	50000,
75 	52000,
76 };
77 
cdns_ti_readl(struct cdns_ti * data,u32 offset)78 static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
79 {
80 	return readl(data->usbss + offset);
81 }
82 
cdns_ti_writel(struct cdns_ti * data,u32 offset,u32 value)83 static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
84 {
85 	writel(value, data->usbss + offset);
86 }
87 
cdns_ti_probe(struct udevice * dev)88 static int cdns_ti_probe(struct udevice *dev)
89 {
90 	struct cdns_ti *data = dev_get_plat(dev);
91 	struct clk usb2_refclk;
92 	int modestrap_mode;
93 	unsigned long rate;
94 	int rate_code, i;
95 	u32 reg;
96 	int ret;
97 
98 	data->dev = dev;
99 
100 	data->usbss = dev_remap_addr_index(dev, 0);
101 	if (!data->usbss)
102 		return -EINVAL;
103 
104 	ret = clk_get_by_name(dev, "usb2_refclk", &usb2_refclk);
105 	if (ret) {
106 		dev_err(dev, "Failed to get usb2_refclk\n");
107 		return ret;
108 	}
109 
110 	rate = clk_get_rate(&usb2_refclk);
111 	rate /= 1000;	/* To KHz */
112 	for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) {
113 		if (cdns_ti_rate_table[i] == rate)
114 			break;
115 	}
116 
117 	if (i == ARRAY_SIZE(cdns_ti_rate_table)) {
118 		dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
119 		return -EINVAL;
120 	}
121 
122 	rate_code = i;
123 
124 	/* assert RESET */
125 	reg = cdns_ti_readl(data, USBSS_W1);
126 	reg &= ~USBSS_W1_PWRUP_RST;
127 	cdns_ti_writel(data, USBSS_W1, reg);
128 
129 	/* set static config */
130 	reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
131 	reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
132 	reg |= rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;
133 
134 	reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
135 	data->vbus_divider = dev_read_bool(dev, "ti,vbus-divider");
136 	if (data->vbus_divider)
137 		reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;
138 
139 	cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
140 	reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
141 
142 	/* set USB2_ONLY mode if requested */
143 	reg = cdns_ti_readl(data, USBSS_W1);
144 	data->usb2_only = dev_read_bool(dev, "ti,usb2-only");
145 	if (data->usb2_only)
146 		reg |= USBSS_W1_USB2_ONLY;
147 
148 	/* set modestrap  */
149 	if (dev_read_bool(dev, "ti,modestrap-host"))
150 		modestrap_mode = USBSS_MODESTRAP_MODE_HOST;
151 	else if (dev_read_bool(dev, "ti,modestrap-peripheral"))
152 		modestrap_mode = USBSS_MODESTRAP_MODE_PERIPHERAL;
153 	else
154 		modestrap_mode = USBSS_MODESTRAP_MODE_NONE;
155 
156 	reg |= USBSS_W1_MODESTRAP_SEL;
157 	reg &= ~USBSS_W1_MODESTRAP_MASK;
158 	reg |= modestrap_mode << USBSS_W1_MODESTRAP_SHIFT;
159 	cdns_ti_writel(data, USBSS_W1, reg);
160 
161 	/* de-assert RESET */
162 	reg |= USBSS_W1_PWRUP_RST;
163 	cdns_ti_writel(data, USBSS_W1, reg);
164 
165 	return 0;
166 }
167 
cdns_ti_remove(struct udevice * dev)168 static int cdns_ti_remove(struct udevice *dev)
169 {
170 	struct cdns_ti *data = dev_get_plat(dev);
171 	u32 reg;
172 
173 	/* put device back to RESET*/
174 	reg = cdns_ti_readl(data, USBSS_W1);
175 	reg &= ~USBSS_W1_PWRUP_RST;
176 	cdns_ti_writel(data, USBSS_W1, reg);
177 
178 	return 0;
179 }
180 
181 static const struct udevice_id cdns_ti_of_match[] = {
182 	{ .compatible = "ti,j721e-usb", },
183 	{},
184 };
185 
186 U_BOOT_DRIVER(cdns_ti) = {
187 	.name = "cdns-ti",
188 	.id = UCLASS_NOP,
189 	.of_match = cdns_ti_of_match,
190 	.bind = cdns3_bind,
191 	.probe = cdns_ti_probe,
192 	.remove = cdns_ti_remove,
193 	.plat_auto	= sizeof(struct cdns_ti),
194 	.flags = DM_FLAG_OS_PREPARE,
195 };
196