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 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 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 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 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 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 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 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 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