blob: 99519602eb2c66299445163fafcdb3e065c89eda [file] [log] [blame]
Sjoerd Simons3ca8c4f2024-05-06 15:38:41 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * TI AM62 specific glue layer for DWC3
4 */
5
6#include <dm.h>
7#include <dm/device_compat.h>
8#include <regmap.h>
9#include <syscon.h>
10#include <asm/io.h>
11
12#include "dwc3-generic.h"
13
14#define USBSS_MODE_CONTROL 0x1c
15#define USBSS_PHY_CONFIG 0x8
16#define USBSS_PHY_VBUS_SEL_MASK GENMASK(2, 1)
17#define USBSS_PHY_VBUS_SEL_SHIFT 1
18#define USBSS_MODE_VALID BIT(0)
19#define PHY_PLL_REFCLK_MASK GENMASK(3, 0)
20static const int dwc3_ti_am62_rate_table[] = { /* in KHZ */
21 9600,
22 10000,
23 12000,
24 19200,
25 20000,
26 24000,
27 25000,
28 26000,
29 38400,
30 40000,
31 58000,
32 50000,
33 52000,
34};
35
36static void dwc3_ti_am62_glue_configure(struct udevice *dev, int index,
37 enum usb_dr_mode mode)
38{
39 struct clk usb2_refclk;
40 int rate_code, i, ret;
41 unsigned long rate;
42 u32 reg;
43 void *usbss;
44 bool vbus_divider;
45 struct regmap *syscon;
46 struct ofnode_phandle_args args;
47
48 usbss = dev_remap_addr_index(dev, 0);
49 if (IS_ERR(usbss)) {
50 dev_err(dev, "can't map IOMEM resource\n");
51 return;
52 }
53
54 ret = clk_get_by_name(dev, "ref", &usb2_refclk);
55 if (ret) {
56 dev_err(dev, "can't get usb2_refclk\n");
57 return;
58 }
59
60 /* Calculate the rate code */
61 rate = clk_get_rate(&usb2_refclk);
62 rate /= 1000; /* To KHz */
63 for (i = 0; i < ARRAY_SIZE(dwc3_ti_am62_rate_table); i++) {
64 if (dwc3_ti_am62_rate_table[i] == rate)
65 break;
66 }
67
68 if (i == ARRAY_SIZE(dwc3_ti_am62_rate_table)) {
69 dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
70 return;
71 }
72
73 rate_code = i;
74
75 /* Read the syscon property */
76 syscon = syscon_regmap_lookup_by_phandle(dev, "ti,syscon-phy-pll-refclk");
77 if (IS_ERR(syscon)) {
78 dev_err(dev, "unable to get ti,syscon-phy-pll-refclk regmap\n");
79 return;
80 }
81
82 ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "ti,syscon-phy-pll-refclk", NULL, 1,
83 0, &args);
84 if (ret)
85 return;
86
87 /* Program PHY PLL refclk by reading syscon property */
88 ret = regmap_update_bits(syscon, args.args[0], PHY_PLL_REFCLK_MASK, rate_code);
89 if (ret) {
90 dev_err(dev, "failed to set phy pll reference clock rate\n");
91 return;
92 }
93
94 /* VBUS divider select */
95 reg = readl(usbss + USBSS_PHY_CONFIG);
96 vbus_divider = dev_read_bool(dev, "ti,vbus-divider");
97 if (vbus_divider)
98 reg |= 1 << USBSS_PHY_VBUS_SEL_SHIFT;
99
100 writel(reg, usbss + USBSS_PHY_CONFIG);
101
102 /* Set mode valid */
103 reg = readl(usbss + USBSS_MODE_CONTROL);
104 reg |= USBSS_MODE_VALID;
105 writel(reg, usbss + USBSS_MODE_CONTROL);
106}
107
108struct dwc3_glue_ops ti_am62_ops = {
109 .glue_configure = dwc3_ti_am62_glue_configure,
110};
111
112static const struct udevice_id dwc3_am62_match[] = {
113 { .compatible = "ti,am62-usb", .data = (ulong)&ti_am62_ops },
114 { /* sentinel */ }
115};
116
117U_BOOT_DRIVER(dwc3_am62_wrapper) = {
118 .name = "dwc3-am62",
119 .id = UCLASS_SIMPLE_BUS,
120 .of_match = dwc3_am62_match,
121 .bind = dwc3_glue_bind,
122 .probe = dwc3_glue_probe,
123 .remove = dwc3_glue_remove,
124 .plat_auto = sizeof(struct dwc3_glue_data),
125};