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