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