1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Rockchip UFS Host Controller driver
4 *
5 * Copyright (C) 2024 Rockchip Electronics Co.Ltd.
6 */
7
8 #include <asm/io.h>
9 #include <clk.h>
10 #include <common.h>
11 #include <dm.h>
12 #include <linux/err.h>
13 #include <linux/ioport.h>
14 #include <reset.h>
15 #include <ufs.h>
16
17 #include "ufs.h"
18 #include "unipro.h"
19 #include "ufs-rockchip.h"
20
21 extern int ufshcd_dme_enable(struct ufs_hba *hba);
22
ufs_rockchip_hce_enable_notify(struct ufs_hba * hba,enum ufs_notify_change_status status)23 static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba,
24 enum ufs_notify_change_status status)
25 {
26 int err = 0;
27
28 if (status == POST_CHANGE) {
29 ufshcd_dme_reset(hba);
30 ufshcd_dme_enable(hba);
31
32 if (hba->ops->phy_initialization) {
33 err = hba->ops->phy_initialization(hba);
34 if (err) {
35 dev_err(hba->dev, "Phy setup failed (%d)\n", err);
36 }
37 }
38 }
39
40 return err;
41 }
42
ufs_rockchip_startup_notify(struct ufs_hba * hba,enum ufs_notify_change_status status)43 static int ufs_rockchip_startup_notify(struct ufs_hba *hba,
44 enum ufs_notify_change_status status)
45 {
46 int err = 0;
47
48 if (status == POST_CHANGE) {
49 if (hba->ops->phy_parameter_initialization) {
50 err = hba->ops->phy_parameter_initialization(hba);
51 if (err) {
52 dev_err(hba->dev, "Phy setup failed (%d)\n", err);
53 }
54 }
55 }
56
57 return err;
58 }
59
60 static const unsigned char rk3576_phy_value[15][4] = {
61 {0x03, 0x38, 0x50, 0x80},
62 {0x03, 0x14, 0x58, 0x80},
63 {0x03, 0x26, 0x58, 0x80},
64 {0x03, 0x49, 0x58, 0x80},
65 {0x03, 0x5A, 0x58, 0x80},
66 {0xC3, 0x38, 0x50, 0xC0},
67 {0xC3, 0x14, 0x58, 0xC0},
68 {0xC3, 0x26, 0x58, 0xC0},
69 {0xC3, 0x49, 0x58, 0xC0},
70 {0xC3, 0x5A, 0x58, 0xC0},
71 {0x43, 0x38, 0x50, 0xC0},
72 {0x43, 0x14, 0x58, 0xC0},
73 {0x43, 0x26, 0x58, 0xC0},
74 {0x43, 0x49, 0x58, 0xC0},
75 {0x43, 0x5A, 0x58, 0xC0}
76 };
77
ufs_rockchip_rk3576_phy_parameter_init(struct ufs_hba * hba)78 static int ufs_rockchip_rk3576_phy_parameter_init(struct ufs_hba *hba)
79 {
80 struct ufs_rockchip_host *host = dev_get_priv(hba->dev);
81 int try_case = host->phy_config_mode, value;
82
83 ufs_sys_writel(host->mphy_base, 0x80, 0x08C);
84 ufs_sys_writel(host->mphy_base, 0xB5, 0x110);
85 ufs_sys_writel(host->mphy_base, 0xB5, 0x250);
86
87 value = rk3576_phy_value[try_case][0];
88 ufs_sys_writel(host->mphy_base, value, 0x134);
89 ufs_sys_writel(host->mphy_base, value, 0x274);
90
91 value = rk3576_phy_value[try_case][1];
92 ufs_sys_writel(host->mphy_base, value, 0x0E0);
93 ufs_sys_writel(host->mphy_base, value, 0x220);
94
95 value = rk3576_phy_value[try_case][2];
96 ufs_sys_writel(host->mphy_base, value, 0x164);
97 ufs_sys_writel(host->mphy_base, value, 0x2A4);
98
99 value = rk3576_phy_value[try_case][3];
100 ufs_sys_writel(host->mphy_base, value, 0x178);
101 ufs_sys_writel(host->mphy_base, value, 0x2B8);
102
103 ufs_sys_writel(host->mphy_base, 0x18, 0x1B0);
104 ufs_sys_writel(host->mphy_base, 0x18, 0x2F0);
105
106 ufs_sys_writel(host->mphy_base, 0xC0, 0x120);
107 ufs_sys_writel(host->mphy_base, 0xC0, 0x260);
108
109 ufs_sys_writel(host->mphy_base, 0x03, 0x094);
110
111 ufs_sys_writel(host->mphy_base, 0x03, 0x1B4);
112 ufs_sys_writel(host->mphy_base, 0x03, 0x2F4);
113
114 ufs_sys_writel(host->mphy_base, 0xC0, 0x08C);
115 udelay(1);
116 ufs_sys_writel(host->mphy_base, 0x00, 0x08C);
117
118 udelay(200);
119
120 return 0;
121 }
122
ufs_rockchip_rk3576_phy_init(struct ufs_hba * hba)123 static int ufs_rockchip_rk3576_phy_init(struct ufs_hba *hba)
124 {
125 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(PA_LOCAL_TX_LCC_ENABLE, 0x0), 0x0);
126 /* enable the mphy DME_SET cfg */
127 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x200, 0x0), 0x40);
128 for (int i = 0; i < 2; i++) {
129 /* Configuration M-TX */
130 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xaa, SEL_TX_LANE0 + i), 0x06);
131 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xa9, SEL_TX_LANE0 + i), 0x02);
132 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xad, SEL_TX_LANE0 + i), 0x44);
133 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xac, SEL_TX_LANE0 + i), 0xe6);
134 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xab, SEL_TX_LANE0 + i), 0x07);
135 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x94, SEL_TX_LANE0 + i), 0x93);
136 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x93, SEL_TX_LANE0 + i), 0xc9);
137 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x7f, SEL_TX_LANE0 + i), 0x00);
138 /* Configuration M-RX */
139 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x12, SEL_RX_LANE0 + i), 0x06);
140 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x11, SEL_RX_LANE0 + i), 0x00);
141 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x1d, SEL_RX_LANE0 + i), 0x58);
142 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x1c, SEL_RX_LANE0 + i), 0x8c);
143 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x1b, SEL_RX_LANE0 + i), 0x02);
144 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x25, SEL_RX_LANE0 + i), 0xf6);
145 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x2f, SEL_RX_LANE0 + i), 0x69);
146 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x1e, SEL_RX_LANE0 + i), 0x18);
147 }
148
149 /* disable the mphy DME_SET cfg */
150 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x200, 0x0), 0x00);
151
152 /* start link up */
153 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_TX_ENDIAN, 0), 0x0);
154 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_RX_ENDIAN, 0), 0x0);
155 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID, 0), 0x0);
156 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID_VALID, 0), 0x1);
157 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_PEERDEVICEID, 0), 0x1);
158 ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_CONNECTIONSTATE, 0), 0x1);
159
160 return 0;
161 }
162
ufs_rockchip_common_init(struct ufs_hba * hba)163 static int ufs_rockchip_common_init(struct ufs_hba *hba)
164 {
165 struct udevice *dev = hba->dev;
166 struct ufs_rockchip_host *host = dev_get_priv(dev);
167 struct resource res;
168 int err = 0;
169
170 /* system control register for hci */
171 err = dev_read_resource_byname(dev, "hci_grf", &res);
172 if (err) {
173 dev_err(dev, "cannot ioremap for hci system control register\n");
174 return -ENODEV;
175 }
176 host->ufs_sys_ctrl = (void *)(res.start);
177
178 /* system control register for mphy */
179 err = dev_read_resource_byname(dev, "mphy_grf", &res);
180 if (err) {
181 dev_err(dev, "cannot ioremap for mphy system control register\n");
182 return -ENODEV;
183 }
184 host->ufs_phy_ctrl = (void *)(res.start);
185
186 /* mphy base register */
187 err = dev_read_resource_byname(dev, "mphy", &res);
188 if (err) {
189 dev_err(dev, "cannot ioremap for mphy base register\n");
190 return -ENODEV;
191 }
192 host->mphy_base = (void *)(res.start);
193
194 host->phy_config_mode = dev_read_u32_default(dev, "ufs-phy-config-mode", 0);
195
196 err = reset_get_bulk(dev, &host->rsts);
197 if (err) {
198 dev_err(dev, "Can't get reset: %d\n", err);
199 return err;
200 }
201
202 host->hba = hba;
203
204 return 0;
205 }
206
ufs_rockchip_rk3576_init(struct ufs_hba * hba)207 static int ufs_rockchip_rk3576_init(struct ufs_hba *hba)
208 {
209 struct udevice *dev = hba->dev;
210 struct ufs_rockchip_host *host = dev_get_priv(dev);
211 int ret = 0;
212
213 ret = ufs_rockchip_common_init(hba);
214 if (ret) {
215 dev_err(hba->dev, "%s: ufs common init fail\n", __func__);
216 return ret;
217 }
218
219 /* UFS PHY select 26M from ppll */
220 writel(0x00030002, 0x2722030C);
221 /* Set UFS_REFCLK, UFS_RSTN */
222 writel(0x00FF0011, 0x2604B398);
223
224 /* Reset ufs controller and device */
225 reset_assert_bulk(&host->rsts);
226 writel(0x00100000, 0x2604B400);
227
228 udelay(20);
229
230 writel(0x00100010, 0x2604B400);
231 reset_deassert_bulk(&host->rsts);
232
233 udelay(20);
234
235 return 0;
236 }
237
238 static struct ufs_hba_ops ufs_hba_rk3576_vops = {
239 .init = ufs_rockchip_rk3576_init,
240 .phy_initialization = ufs_rockchip_rk3576_phy_init,
241 .hce_enable_notify = ufs_rockchip_hce_enable_notify,
242 .link_startup_notify = ufs_rockchip_startup_notify,
243 .phy_parameter_initialization = ufs_rockchip_rk3576_phy_parameter_init,
244 };
245
246 static const struct udevice_id ufs_rockchip_of_match[] = {
247 { .compatible = "rockchip,rk3576-ufs", .data = (ulong)&ufs_hba_rk3576_vops},
248 {},
249 };
250
ufs_rockchip_probe(struct udevice * dev)251 static int ufs_rockchip_probe(struct udevice *dev)
252 {
253 struct ufs_hba_ops *ops = (struct ufs_hba_ops *)dev_get_driver_data(dev);
254 int err;
255
256 err = ufshcd_probe(dev, ops);
257 if (err)
258 dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
259
260 return err;
261 }
262
ufs_rockchip_bind(struct udevice * dev)263 static int ufs_rockchip_bind(struct udevice *dev)
264 {
265 struct udevice *scsi_dev;
266
267 return ufs_scsi_bind(dev, &scsi_dev);
268 }
269
270 U_BOOT_DRIVER(ti_j721e_ufs) = {
271 .name = "ufshcd-rockchip",
272 .id = UCLASS_UFS,
273 .of_match = ufs_rockchip_of_match,
274 .probe = ufs_rockchip_probe,
275 .bind = ufs_rockchip_bind,
276 .priv_auto_alloc_size = sizeof(struct ufs_rockchip_host),
277 };
278