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