1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2020 Rockchip Electronics Co., Ltd 4 * 5 * Based on phy-rockchip-inno-usb3.c in Linux Kernel. 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <dm/lists.h> 11 #include <dm/of_access.h> 12 #include <generic-phy.h> 13 #include <power/regulator.h> 14 #include <regmap.h> 15 #include <reset.h> 16 #include <syscon.h> 17 #include <asm/io.h> 18 #include <asm/arch/clock.h> 19 20 #define usleep_range(a, b) udelay((b)) 21 22 #define U3PHY_PORT_NUM 2 23 #define U3PHY_MAX_CLKS 4 24 #define BIT_WRITEABLE_SHIFT 16 25 #define SCHEDULE_DELAY (60 * HZ) 26 27 #define U3PHY_APB_RST BIT(0) 28 #define U3PHY_POR_RST BIT(1) 29 #define U3PHY_MAC_RST BIT(2) 30 31 struct rockchip_u3phy; 32 struct rockchip_u3phy_port; 33 34 enum rockchip_u3phy_type { 35 U3PHY_TYPE_PIPE, 36 U3PHY_TYPE_UTMI, 37 }; 38 39 enum rockchip_u3phy_pipe_pwr { 40 PIPE_PWR_P0 = 0, 41 PIPE_PWR_P1 = 1, 42 PIPE_PWR_P2 = 2, 43 PIPE_PWR_P3 = 3, 44 PIPE_PWR_MAX = 4, 45 }; 46 47 enum rockchip_u3phy_rest_req { 48 U3_POR_RSTN = 0, 49 U2_POR_RSTN = 1, 50 PIPE_MAC_RSTN = 2, 51 UTMI_MAC_RSTN = 3, 52 PIPE_APB_RSTN = 4, 53 UTMI_APB_RSTN = 5, 54 U3PHY_RESET_MAX = 6, 55 }; 56 57 enum rockchip_u3phy_utmi_state { 58 PHY_UTMI_HS_ONLINE = 0, 59 PHY_UTMI_DISCONNECT = 1, 60 PHY_UTMI_CONNECT = 2, 61 PHY_UTMI_FS_LS_ONLINE = 4, 62 }; 63 64 /* 65 * @rvalue: reset value 66 * @dvalue: desired value 67 */ 68 struct u3phy_reg { 69 unsigned int offset; 70 unsigned int bitend; 71 unsigned int bitstart; 72 unsigned int rvalue; 73 unsigned int dvalue; 74 }; 75 76 struct rockchip_u3phy_grfcfg { 77 struct u3phy_reg um_suspend; 78 struct u3phy_reg ls_det_en; 79 struct u3phy_reg ls_det_st; 80 struct u3phy_reg um_ls; 81 struct u3phy_reg um_hstdct; 82 struct u3phy_reg u2_only_ctrl; 83 struct u3phy_reg u3_disable; 84 struct u3phy_reg pp_pwr_st; 85 struct u3phy_reg pp_pwr_en[PIPE_PWR_MAX]; 86 }; 87 88 /** 89 * struct rockchip_u3phy_apbcfg: usb3-phy apb configuration. 90 * @u2_pre_emp: usb2-phy pre-emphasis tuning. 91 * @u2_pre_emp_sth: usb2-phy pre-emphasis strength tuning. 92 * @u2_odt_tuning: usb2-phy odt 45ohm tuning. 93 */ 94 struct rockchip_u3phy_apbcfg { 95 unsigned int u2_pre_emp; 96 unsigned int u2_pre_emp_sth; 97 unsigned int u2_odt_tuning; 98 }; 99 100 struct rockchip_u3phy_cfg { 101 unsigned int reg; 102 const struct rockchip_u3phy_grfcfg grfcfg; 103 104 int (*phy_tuning)(struct rockchip_u3phy *u3phy, 105 struct rockchip_u3phy_port *u3phy_port, 106 const struct device_node *child_np); 107 }; 108 109 struct rockchip_u3phy_port { 110 void __iomem *base; 111 unsigned int index; 112 unsigned char type; 113 bool refclk_25m_quirk; 114 struct mutex mutex; /* mutex for updating register */ 115 }; 116 117 struct rockchip_u3phy { 118 struct udevice *dev; 119 struct regmap *u3phy_grf; 120 struct regmap *grf; 121 struct udevice *vbus_supply; 122 struct reset_ctl rsts[U3PHY_RESET_MAX]; 123 struct rockchip_u3phy_apbcfg apbcfg; 124 const struct rockchip_u3phy_cfg *cfgs; 125 struct rockchip_u3phy_port ports[U3PHY_PORT_NUM]; 126 }; 127 128 static inline int param_write(void __iomem *base, 129 const struct u3phy_reg *reg, bool desired) 130 { 131 unsigned int val, mask; 132 unsigned int tmp = desired ? reg->dvalue : reg->rvalue; 133 int ret = 0; 134 135 mask = GENMASK(reg->bitend, reg->bitstart); 136 val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); 137 ret = regmap_write(base, reg->offset, val); 138 139 return ret; 140 } 141 142 static inline bool param_exped(void __iomem *base, 143 const struct u3phy_reg *reg, 144 unsigned int value) 145 { 146 int ret; 147 unsigned int tmp, orig; 148 unsigned int mask = GENMASK(reg->bitend, reg->bitstart); 149 150 ret = regmap_read(base, reg->offset, &orig); 151 if (ret) 152 return false; 153 154 tmp = (orig & mask) >> reg->bitstart; 155 return tmp == value; 156 } 157 158 int rockchip_u3phy_uboot_init(void) 159 { 160 struct udevice *udev; 161 int ret; 162 163 ret = uclass_get_device_by_name(UCLASS_PHY, "usb3-phy", &udev); 164 if (ret) 165 pr_err("%s: get usb3-phy node failed: %d\n", __func__, ret); 166 167 (void)udev; 168 169 return ret; 170 } 171 172 static int rockchip_u3phy_init(struct phy *phy) 173 { 174 return 0; 175 } 176 177 static int rockchip_u3phy_exit(struct phy *phy) 178 { 179 return 0; 180 } 181 182 static int rockchip_u3phy_power_on(struct phy *phy) 183 { 184 struct udevice *parent = dev_get_parent(phy->dev); 185 struct rockchip_u3phy *u3phy = dev_get_priv(parent); 186 int ret = 0; 187 188 /* Vbus regulator */ 189 if (!u3phy->vbus_supply) { 190 ret = device_get_supply_regulator(parent, "vbus-supply", 191 &u3phy->vbus_supply); 192 if (ret == -ENOENT) { 193 pr_info("%s: Can't get VBus regulator!\n", __func__); 194 return 0; 195 } 196 197 ret = regulator_set_enable(u3phy->vbus_supply, true); 198 if (ret) { 199 pr_err("%s: Failed to set VBus supply\n", __func__); 200 return ret; 201 } 202 } 203 204 return 0; 205 } 206 207 static int rockchip_u3phy_power_off(struct phy *phy) 208 { 209 struct udevice *parent = dev_get_parent(phy->dev); 210 struct rockchip_u3phy *u3phy = dev_get_priv(parent); 211 int ret = 0; 212 213 /* Turn off vbus regulator */ 214 if (u3phy->vbus_supply) { 215 ret = regulator_set_enable(u3phy->vbus_supply, false); 216 if (ret) { 217 pr_err("%s: Failed to set VBus supply\n", __func__); 218 return ret; 219 } 220 221 u3phy->vbus_supply = NULL; 222 } 223 224 return 0; 225 } 226 227 static int rockchip_u3phy_bind(struct udevice *parent) 228 { 229 struct udevice *dev; 230 ofnode node; 231 const char *name; 232 int ret; 233 234 dev_for_each_subnode(node, parent) { 235 if (!ofnode_valid(node)) { 236 debug("%s: %s subnode not found", __func__, parent->name); 237 return -ENXIO; 238 } 239 240 name = ofnode_get_name(node); 241 debug("%s: subnode %s\n", __func__, name); 242 243 ret = device_bind_driver_to_node(parent, "rockchip_u3phy_port", 244 name, node, &dev); 245 if (ret) { 246 pr_err("%s: '%s' cannot bind 'rockchip_u3phy_port'\n", 247 __func__, name); 248 return ret; 249 } 250 } 251 252 return 0; 253 } 254 255 static const char *get_rest_name(enum rockchip_u3phy_rest_req rst) 256 { 257 switch (rst) { 258 case U2_POR_RSTN: 259 return "u3phy-u2-por"; 260 case U3_POR_RSTN: 261 return "u3phy-u3-por"; 262 case PIPE_MAC_RSTN: 263 return "u3phy-pipe-mac"; 264 case UTMI_MAC_RSTN: 265 return "u3phy-utmi-mac"; 266 case UTMI_APB_RSTN: 267 return "u3phy-utmi-apb"; 268 case PIPE_APB_RSTN: 269 return "u3phy-pipe-apb"; 270 default: 271 return "invalid"; 272 } 273 } 274 275 static void rockchip_u3phy_rest_deassert(struct rockchip_u3phy *u3phy, 276 unsigned int flag) 277 { 278 int rst; 279 280 if (flag & U3PHY_APB_RST) { 281 dev_dbg(u3phy->dev, "deassert APB bus interface reset\n"); 282 for (rst = PIPE_APB_RSTN; rst <= UTMI_APB_RSTN; rst++) { 283 if (u3phy->rsts[rst].dev) 284 reset_deassert(&u3phy->rsts[rst]); 285 } 286 } 287 288 if (flag & U3PHY_POR_RST) { 289 usleep_range(12, 15); 290 dev_dbg(u3phy->dev, "deassert u2 and u3 phy power on reset\n"); 291 for (rst = U3_POR_RSTN; rst <= U2_POR_RSTN; rst++) { 292 if (u3phy->rsts[rst].dev) 293 reset_deassert(&u3phy->rsts[rst]); 294 } 295 } 296 297 if (flag & U3PHY_MAC_RST) { 298 usleep_range(1200, 1500); 299 dev_dbg(u3phy->dev, "deassert pipe and utmi MAC reset\n"); 300 for (rst = PIPE_MAC_RSTN; rst <= UTMI_MAC_RSTN; rst++) 301 if (u3phy->rsts[rst].dev) 302 reset_deassert(&u3phy->rsts[rst]); 303 } 304 } 305 306 static void rockchip_u3phy_rest_assert(struct rockchip_u3phy *u3phy) 307 { 308 int rst; 309 310 dev_dbg(u3phy->dev, "assert u3phy reset\n"); 311 for (rst = 0; rst < U3PHY_RESET_MAX; rst++) 312 if (u3phy->rsts[rst].dev) 313 reset_assert(&u3phy->rsts[rst]); 314 } 315 316 static int rockchip_u3phy_parse_dt(struct rockchip_u3phy *u3phy, 317 struct udevice *udev) 318 319 { 320 int i, ret = 0; 321 322 for (i = 0; i < U3PHY_RESET_MAX; i++) { 323 ret = reset_get_by_name(udev, get_rest_name(i), 324 &u3phy->rsts[i]); 325 if (ret) { 326 dev_info(udev, "no %s reset control specified\n", 327 get_rest_name(i)); 328 } 329 } 330 331 return ret; 332 } 333 334 static int rockchip_u3phy_port_init(struct rockchip_u3phy *u3phy, 335 struct rockchip_u3phy_port *u3phy_port, 336 const struct device_node *child_np) 337 { 338 int ret; 339 340 dev_dbg(u3phy->dev, "u3phy port initialize\n"); 341 342 mutex_init(&u3phy_port->mutex); 343 344 u3phy_port->base = (void __iomem *)ofnode_get_addr(np_to_ofnode(child_np)); 345 if (IS_ERR(u3phy_port->base)) { 346 dev_err(u3phy->dev, "failed to remap phy regs\n"); 347 return PTR_ERR(u3phy_port->base); 348 } 349 350 if (!of_node_cmp(child_np->name, "pipe")) { 351 u3phy_port->type = U3PHY_TYPE_PIPE; 352 u3phy_port->refclk_25m_quirk = 353 ofnode_read_bool(np_to_ofnode(child_np), 354 "rockchip,refclk-25m-quirk"); 355 } else { 356 u3phy_port->type = U3PHY_TYPE_UTMI; 357 } 358 359 if (u3phy->cfgs->phy_tuning) { 360 dev_dbg(u3phy->dev, "do u3phy tuning\n"); 361 ret = u3phy->cfgs->phy_tuning(u3phy, u3phy_port, child_np); 362 if (ret) 363 return ret; 364 } 365 366 return 0; 367 } 368 369 static int rockchip_u3phy_probe(struct udevice *udev) 370 { 371 const struct udevice_id *of_match = udev->driver->of_match; 372 struct rockchip_u3phy *u3phy = dev_get_priv(udev); 373 const struct rockchip_u3phy_cfg *phy_cfgs; 374 ofnode child_np; 375 u32 reg[2], index; 376 int ret = 0; 377 378 while (of_match->compatible) { 379 if (device_is_compatible(udev, of_match->compatible)) 380 break; 381 of_match++; 382 } 383 384 if (!of_match || !of_match->data) { 385 dev_err(udev, "phy-cfgs are not assigned!\n"); 386 return -EINVAL; 387 } 388 389 if (ofnode_read_u32_array(dev_ofnode(udev), "reg", reg, 2)) { 390 dev_err(udev, "could not read reg\n"); 391 return -EINVAL; 392 } 393 394 u3phy->dev = udev; 395 phy_cfgs = (const struct rockchip_u3phy_cfg *)of_match->data; 396 397 /* find out a proper config which can be matched with dt. */ 398 index = 0; 399 while (phy_cfgs[index].reg) { 400 if (phy_cfgs[index].reg == reg[1]) { 401 u3phy->cfgs = &phy_cfgs[index]; 402 break; 403 } 404 ++index; 405 } 406 407 if (!u3phy->cfgs) { 408 dev_err(udev, "no phy-cfgs can be matched\n"); 409 return -EINVAL; 410 } 411 412 ret = rockchip_u3phy_parse_dt(u3phy, udev); 413 if (ret) { 414 dev_err(udev, "parse dt failed, ret(%d)\n", ret); 415 return ret; 416 } 417 418 rockchip_u3phy_rest_assert(u3phy); 419 rockchip_u3phy_rest_deassert(u3phy, U3PHY_APB_RST | U3PHY_POR_RST); 420 421 index = 0; 422 ofnode_for_each_subnode(child_np, udev->node) { 423 struct rockchip_u3phy_port *u3phy_port = &u3phy->ports[index]; 424 425 u3phy_port->index = index; 426 ret = rockchip_u3phy_port_init(u3phy, u3phy_port, 427 ofnode_to_np(child_np)); 428 if (ret) { 429 dev_err(udev, "u3phy port init failed,ret(%d)\n", ret); 430 goto put_child; 431 } 432 433 /* to prevent out of boundary */ 434 if (++index >= U3PHY_PORT_NUM) 435 break; 436 } 437 438 rockchip_u3phy_rest_deassert(u3phy, U3PHY_MAC_RST); 439 440 dev_info(udev, "Rockchip u3phy initialized successfully\n"); 441 return 0; 442 443 put_child: 444 of_node_put(ofnode_to_np(child_np)); 445 return ret; 446 } 447 448 static int rk3328_u3phy_tuning(struct rockchip_u3phy *u3phy, 449 struct rockchip_u3phy_port *u3phy_port, 450 const struct device_node *child_np) 451 { 452 if (u3phy_port->type == U3PHY_TYPE_UTMI) { 453 /* 454 * For rk3328 SoC, pre-emphasis and pre-emphasis strength must 455 * be written as one fixed value as below. 456 * 457 * Dissimilarly, the odt 45ohm value should be flexibly tuninged 458 * for the different boards to adjust HS eye height, so its 459 * value can be assigned in DT in code design. 460 */ 461 462 /* {bits[2:0]=111}: always enable pre-emphasis */ 463 u3phy->apbcfg.u2_pre_emp = 0x0f; 464 465 /* {bits[5:3]=000}: pre-emphasis strength as the weakest */ 466 u3phy->apbcfg.u2_pre_emp_sth = 0x41; 467 468 /* {bits[4:0]=10101}: odt 45ohm tuning */ 469 u3phy->apbcfg.u2_odt_tuning = 0xb5; 470 471 /* optional override of the odt 45ohm tuning */ 472 ofnode_read_u32(np_to_ofnode(child_np), 473 "rockchip,odt-val-tuning", 474 &u3phy->apbcfg.u2_odt_tuning); 475 476 writel(u3phy->apbcfg.u2_pre_emp, u3phy_port->base + 0x030); 477 writel(u3phy->apbcfg.u2_pre_emp_sth, u3phy_port->base + 0x040); 478 writel(u3phy->apbcfg.u2_odt_tuning, u3phy_port->base + 0x11c); 479 } else if (u3phy_port->type == U3PHY_TYPE_PIPE) { 480 if (u3phy_port->refclk_25m_quirk) { 481 dev_dbg(u3phy->dev, "switch to 25m refclk\n"); 482 /* ref clk switch to 25M */ 483 writel(0x64, u3phy_port->base + 0x11c); 484 writel(0x64, u3phy_port->base + 0x028); 485 writel(0x01, u3phy_port->base + 0x020); 486 writel(0x21, u3phy_port->base + 0x030); 487 writel(0x06, u3phy_port->base + 0x108); 488 writel(0x00, u3phy_port->base + 0x118); 489 } else { 490 /* configure for 24M ref clk */ 491 writel(0x80, u3phy_port->base + 0x10c); 492 writel(0x01, u3phy_port->base + 0x118); 493 writel(0x38, u3phy_port->base + 0x11c); 494 writel(0x83, u3phy_port->base + 0x020); 495 writel(0x02, u3phy_port->base + 0x108); 496 } 497 498 /* Enable SSC */ 499 udelay(3); 500 writel(0x08, u3phy_port->base + 0x000); 501 writel(0x0c, u3phy_port->base + 0x120); 502 503 /* Tuning Rx for compliance RJTL test */ 504 writel(0x70, u3phy_port->base + 0x150); 505 writel(0x12, u3phy_port->base + 0x0c8); 506 writel(0x05, u3phy_port->base + 0x148); 507 writel(0x08, u3phy_port->base + 0x068); 508 writel(0xf0, u3phy_port->base + 0x1c4); 509 writel(0xff, u3phy_port->base + 0x070); 510 writel(0x0f, u3phy_port->base + 0x06c); 511 writel(0xe0, u3phy_port->base + 0x060); 512 513 /* 514 * Tuning Tx to increase the bias current 515 * used in TX driver and RX EQ, it can 516 * also increase the voltage of LFPS. 517 */ 518 writel(0x08, u3phy_port->base + 0x180); 519 } else { 520 dev_err(u3phy->dev, "invalid u3phy port type\n"); 521 return -EINVAL; 522 } 523 524 return 0; 525 } 526 527 static struct phy_ops rockchip_u3phy_ops = { 528 .init = rockchip_u3phy_init, 529 .exit = rockchip_u3phy_exit, 530 .power_on= rockchip_u3phy_power_on, 531 .power_off= rockchip_u3phy_power_off, 532 }; 533 534 static const struct rockchip_u3phy_cfg rk3328_u3phy_cfgs[] = { 535 { 536 .reg = 0xff470000, 537 .grfcfg = { 538 .um_suspend = { 0x0004, 15, 0, 0x1452, 0x15d1 }, 539 .u2_only_ctrl = { 0x0020, 15, 15, 0, 1 }, 540 .um_ls = { 0x0030, 5, 4, 0, 1 }, 541 .um_hstdct = { 0x0030, 7, 7, 0, 1 }, 542 .ls_det_en = { 0x0040, 0, 0, 0, 1 }, 543 .ls_det_st = { 0x0044, 0, 0, 0, 1 }, 544 .pp_pwr_st = { 0x0034, 14, 13, 0, 0}, 545 .pp_pwr_en = { {0x0020, 14, 0, 0x0014, 0x0005}, 546 {0x0020, 14, 0, 0x0014, 0x000d}, 547 {0x0020, 14, 0, 0x0014, 0x0015}, 548 {0x0020, 14, 0, 0x0014, 0x001d} }, 549 .u3_disable = { 0x04c4, 15, 0, 0x1100, 0x101}, 550 }, 551 .phy_tuning = rk3328_u3phy_tuning, 552 }, 553 { /* sentinel */ } 554 }; 555 556 static const struct udevice_id rockchip_u3phy_dt_match[] = { 557 { .compatible = "rockchip,rk3328-u3phy", .data = (ulong)&rk3328_u3phy_cfgs }, 558 {} 559 }; 560 561 U_BOOT_DRIVER(rockchip_u3phy_port) = { 562 .name = "rockchip_u3phy_port", 563 .id = UCLASS_PHY, 564 .ops = &rockchip_u3phy_ops, 565 }; 566 567 U_BOOT_DRIVER(rockchip_u3phy) = { 568 .name = "rockchip_u3phy", 569 .id = UCLASS_PHY, 570 .of_match = rockchip_u3phy_dt_match, 571 .probe = rockchip_u3phy_probe, 572 .bind = rockchip_u3phy_bind, 573 .priv_auto_alloc_size = sizeof(struct rockchip_u3phy), 574 }; 575