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