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