ARM: mach-at91: Add compile time option to choose proper timer
[platform/kernel/u-boot.git] / drivers / usb / cdns3 / cdns3-ti.c
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
78 static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
79 {
80         return readl(data->usbss + offset);
81 }
82
83 static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
84 {
85         writel(value, data->usbss + offset);
86 }
87
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, "ref", &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
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 };