blob: 78ceb831b19dda6c2154e0264e879a65831b5bdd [file] [log] [blame]
Minda Chen3592e322025-03-06 14:20:29 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * cdns3-starfive.c - StarFive specific Glue layer for Cadence USB Controller
4 *
5 * Copyright (C) 2024 StarFive Technology Co., Ltd.
6 *
7 * Author: Minda Chen <minda.chen@starfivetech.com>
8 */
9
10#include <asm/io.h>
11#include <clk.h>
12#include <dm.h>
13#include <dm/device_compat.h>
14#include <linux/bitops.h>
15#include <linux/usb/otg.h>
16#include <malloc.h>
17#include <reset.h>
18#include <regmap.h>
19#include <syscon.h>
20
21#include "core.h"
22
23#define USB_STRAP_HOST BIT(17)
24#define USB_STRAP_DEVICE BIT(18)
25#define USB_STRAP_MASK GENMASK(18, 16)
26
27#define USB_SUSPENDM_HOST BIT(19)
28#define USB_SUSPENDM_MASK BIT(19)
29
30#define USB_MISC_CFG_MASK GENMASK(23, 20)
31#define USB_SUSPENDM_BYPS BIT(20)
32#define USB_PLL_EN BIT(22)
33#define USB_REFCLK_MODE BIT(23)
34
35struct cdns_starfive {
36 struct udevice *dev;
37 struct regmap *stg_syscon;
38 struct reset_ctl_bulk resets;
39 struct clk_bulk clks;
40 u32 stg_usb_mode;
41 enum usb_dr_mode mode;
42};
43
44static void cdns_mode_init(struct cdns_starfive *data, enum usb_dr_mode mode)
45{
46 unsigned int strap, suspendm;
47
48 regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
49 USB_MISC_CFG_MASK,
50 USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE);
51
52 switch (mode) {
53 case USB_DR_MODE_HOST:
54 strap = USB_STRAP_HOST;
55 suspendm = USB_SUSPENDM_HOST;
56 break;
57 case USB_DR_MODE_PERIPHERAL:
58 strap = USB_STRAP_DEVICE;
59 suspendm = 0;
60 break;
61 default:
62 return;
63 }
64
65 regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
66 USB_SUSPENDM_MASK | USB_STRAP_MASK,
67 strap | suspendm);
68}
69
70static void cdns_clk_rst_deinit(struct cdns_starfive *data)
71{
72 reset_assert_bulk(&data->resets);
73 clk_disable_bulk(&data->clks);
74}
75
76static int cdns_clk_rst_init(struct cdns_starfive *data)
77{
78 int ret;
79
80 ret = clk_get_bulk(data->dev, &data->clks);
81 if (ret)
82 return ret;
83
84 ret = reset_get_bulk(data->dev, &data->resets);
85 if (ret)
86 goto err_clk;
87
88 ret = clk_enable_bulk(&data->clks);
89 if (ret) {
90 dev_err(data->dev, "clk enable failed: %d\n", ret);
91 goto err_en_clk;
92 }
93
94 ret = reset_deassert_bulk(&data->resets);
95 if (ret) {
96 dev_err(data->dev, "reset deassert failed: %d\n", ret);
97 goto err_reset;
98 }
99
100 return 0;
101
102err_reset:
103 clk_disable_bulk(&data->clks);
104err_en_clk:
105 reset_release_bulk(&data->resets);
106err_clk:
107 clk_release_bulk(&data->clks);
108
109 return ret;
110}
111
112static int cdns_starfive_get_syscon(struct cdns_starfive *data)
113{
114 struct ofnode_phandle_args phandle;
115 int ret;
116
117 ret = dev_read_phandle_with_args(data->dev, "starfive,stg-syscon", NULL, 1, 0,
118 &phandle);
119 if (ret < 0) {
120 dev_err(data->dev, "Can't get stg cfg phandle: %d\n", ret);
121 return ret;
122 }
123
124 data->stg_syscon = syscon_node_to_regmap(phandle.node);
125 if (IS_ERR(data->stg_syscon)) {
126 dev_err(data->dev, "fail to get regmap: %d\n", (int)PTR_ERR(data->stg_syscon));
127 return PTR_ERR(data->stg_syscon);
128 }
129
130 data->stg_usb_mode = phandle.args[0];
131
132 return 0;
133}
134
135static int cdns_starfive_probe(struct udevice *dev)
136{
137 struct cdns_starfive *data = dev_get_plat(dev);
138 enum usb_dr_mode dr_mode;
139 int ret;
140
141 data->dev = dev;
142
143 ret = cdns_starfive_get_syscon(data);
144 if (ret)
145 return ret;
146
147 dr_mode = usb_get_dr_mode(dev_ofnode(dev));
148
149 data->mode = dr_mode;
150 ret = cdns_clk_rst_init(data);
151 if (ret) {
152 dev_err(data->dev, "clk reset failed: %d\n", ret);
153 return ret;
154 }
155 cdns_mode_init(data, dr_mode);
156
157 return 0;
158}
159
160static int cdns_starfive_remove(struct udevice *dev)
161{
162 struct cdns_starfive *data = dev_get_plat(dev);
163
164 cdns_clk_rst_deinit(data);
165 return 0;
166}
167
168static const struct udevice_id cdns_starfive_of_match[] = {
169 { .compatible = "starfive,jh7110-usb", },
170 {},
171};
172
173U_BOOT_DRIVER(cdns_starfive) = {
174 .name = "cdns-starfive",
175 .id = UCLASS_NOP,
176 .of_match = cdns_starfive_of_match,
177 .bind = cdns3_bind,
178 .probe = cdns_starfive_probe,
179 .remove = cdns_starfive_remove,
180 .plat_auto = sizeof(struct cdns_starfive),
181 .flags = DM_FLAG_OS_PREPARE,
182};