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