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