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