1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Rockchip UFS Host Controller driver
*
* Copyright (C) 2025 Rockchip Electronics Co.Ltd.
*/
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/ioport.h>
#include <reset.h>
#include <ufs.h>
#include "ufs.h"
#include "unipro.h"
#include "ufs-rockchip.h"
static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
int err = 0;
if (status != POST_CHANGE)
return 0;
ufshcd_dme_reset(hba);
ufshcd_dme_enable(hba);
if (hba->ops->phy_initialization) {
err = hba->ops->phy_initialization(hba);
if (err)
dev_err(hba->dev,
"Phy init failed (%d)\n", err);
}
return err;
}
static void ufs_rockchip_rk3576_phy_parameter_init(struct ufs_hba *hba)
{
struct ufs_rockchip_host *host = dev_get_priv(hba->dev);
ufs_sys_writel(host->mphy_base, 0x80, CMN_REG23);
ufs_sys_writel(host->mphy_base, 0xB5, TRSV0_REG14);
ufs_sys_writel(host->mphy_base, 0xB5, TRSV1_REG14);
ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG15);
ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG15);
ufs_sys_writel(host->mphy_base, 0x38, TRSV0_REG08);
ufs_sys_writel(host->mphy_base, 0x38, TRSV1_REG08);
ufs_sys_writel(host->mphy_base, 0x50, TRSV0_REG29);
ufs_sys_writel(host->mphy_base, 0x50, TRSV1_REG29);
ufs_sys_writel(host->mphy_base, 0x80, TRSV0_REG2E);
ufs_sys_writel(host->mphy_base, 0x80, TRSV1_REG2E);
ufs_sys_writel(host->mphy_base, 0x18, TRSV0_REG3C);
ufs_sys_writel(host->mphy_base, 0x18, TRSV1_REG3C);
ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG16);
ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG16);
ufs_sys_writel(host->mphy_base, 0x20, TRSV0_REG17);
ufs_sys_writel(host->mphy_base, 0x20, TRSV1_REG17);
ufs_sys_writel(host->mphy_base, 0xC0, TRSV0_REG18);
ufs_sys_writel(host->mphy_base, 0xC0, TRSV1_REG18);
ufs_sys_writel(host->mphy_base, 0x03, CMN_REG25);
ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG3D);
ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG3D);
ufs_sys_writel(host->mphy_base, 0xC0, CMN_REG23);
udelay(1);
ufs_sys_writel(host->mphy_base, 0x00, CMN_REG23);
udelay(200);
}
static int ufs_rockchip_rk3576_phy_init(struct ufs_hba *hba)
{
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(PA_LOCAL_TX_LCC_ENABLE, 0x0), 0x0);
/* enable the mphy DME_SET cfg */
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_ENABLE);
for (int i = 0; i < 2; i++) {
/* Configuration M-TX */
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, SEL_TX_LANE0 + i), 0x06);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, SEL_TX_LANE0 + i), 0x02);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_VALUE, SEL_TX_LANE0 + i), 0x44);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, SEL_TX_LANE0 + i), 0xe6);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, SEL_TX_LANE0 + i), 0x07);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_TASE_VALUE, SEL_TX_LANE0 + i), 0x93);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_BASE_NVALUE, SEL_TX_LANE0 + i), 0xc9);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_POWER_SAVING_CTRL, SEL_TX_LANE0 + i), 0x00);
/* Configuration M-RX */
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, SEL_RX_LANE0 + i), 0x06);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, SEL_RX_LANE0 + i), 0x00);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE, SEL_RX_LANE0 + i), 0x58);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE1, SEL_RX_LANE0 + i), 0x8c);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE2, SEL_RX_LANE0 + i), 0x02);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_OPTION, SEL_RX_LANE0 + i), 0xf6);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_POWER_SAVING_CTRL, SEL_RX_LANE0 + i), 0x69);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_SAVE_DET_CTRL, SEL_RX_LANE0 + i), 0x18);
}
/* disable the mphy DME_SET cfg */
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_DISABLE);
ufs_rockchip_rk3576_phy_parameter_init(hba);
/* start link up */
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_TX_ENDIAN, 0), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_RX_ENDIAN, 0), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID, 0), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID_VALID, 0), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_PEERDEVICEID, 0), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_CONNECTIONSTATE, 0), 0x1);
return 0;
}
static int ufs_rockchip_common_init(struct ufs_hba *hba)
{
struct udevice *dev = hba->dev;
struct ufs_rockchip_host *host = dev_get_priv(dev);
struct resource res;
int err;
/* system control register for hci */
err = dev_read_resource_byname(dev, "hci_grf", &res);
if (err) {
dev_err(dev, "cannot ioremap for hci system control register\n");
return err;
}
host->ufs_sys_ctrl = (void *)(res.start);
/* system control register for mphy */
err = dev_read_resource_byname(dev, "mphy_grf", &res);
if (err) {
dev_err(dev, "cannot ioremap for mphy system control register\n");
return err;
}
host->ufs_phy_ctrl = (void *)(res.start);
/* mphy base register */
err = dev_read_resource_byname(dev, "mphy", &res);
if (err) {
dev_err(dev, "cannot ioremap for mphy base register\n");
return err;
}
host->mphy_base = (void *)(res.start);
host->phy_config_mode = dev_read_u32_default(dev, "ufs-phy-config-mode", 0);
err = reset_get_bulk(dev, &host->rsts);
if (err) {
dev_err(dev, "Can't get reset: %d\n", err);
return err;
}
host->hba = hba;
return 0;
}
static int ufs_rockchip_rk3576_init(struct ufs_hba *hba)
{
int ret = 0;
ret = ufs_rockchip_common_init(hba);
if (ret) {
dev_err(hba->dev, "%s: ufs common init fail\n", __func__);
return ret;
}
return 0;
}
static struct ufs_hba_ops ufs_hba_rk3576_vops = {
.init = ufs_rockchip_rk3576_init,
.phy_initialization = ufs_rockchip_rk3576_phy_init,
.hce_enable_notify = ufs_rockchip_hce_enable_notify,
};
static const struct udevice_id ufs_rockchip_of_match[] = {
{ .compatible = "rockchip,rk3576-ufshc", .data = (ulong)&ufs_hba_rk3576_vops},
{},
};
static int ufs_rockchip_probe(struct udevice *dev)
{
struct ufs_hba_ops *ops = (struct ufs_hba_ops *)dev_get_driver_data(dev);
int err;
err = ufshcd_probe(dev, ops);
if (err)
dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
return err;
}
U_BOOT_DRIVER(rockchip_ufs) = {
.name = "ufshcd-rockchip",
.id = UCLASS_UFS,
.of_match = ufs_rockchip_of_match,
.probe = ufs_rockchip_probe,
.priv_auto = sizeof(struct ufs_rockchip_host),
};
|