Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: ufs: host: ufs-exynos: Add support for FSD UFS HCI

Adds support of UFS HCI which is found in Tesla Full Self-Driving (FSD)
SoC.

Link: https://lore.kernel.org/r/20220610104119.66401-7-alim.akhtar@samsung.com
Co-developed-by: Bharat Uppal <bharat.uppal@samsung.com>
Signed-off-by: Bharat Uppal <bharat.uppal@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Alim Akhtar and committed by
Martin K. Petersen
216f74e8 daa782a5

+141
+140
drivers/ufs/host/ufs-exynos.c
··· 146 146 #define UNIPRO_DME_PWR_REQ_REMOTEL2TIMER1 0x0A8 147 147 #define UNIPRO_DME_PWR_REQ_REMOTEL2TIMER2 0x0AC 148 148 149 + #define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER0 0x78B8 150 + #define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER1 0x78BC 151 + #define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER2 0x78C0 152 + 149 153 /* 150 154 * UFS Protector registers 151 155 */ ··· 1478 1474 return 0; 1479 1475 } 1480 1476 1477 + static int fsd_ufs_pre_link(struct exynos_ufs *ufs) 1478 + { 1479 + int i; 1480 + struct ufs_hba *hba = ufs->hba; 1481 + 1482 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_CLK_PERIOD), 1483 + DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate)); 1484 + ufshcd_dme_set(hba, UIC_ARG_MIB(0x201), 0x12); 1485 + ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40); 1486 + 1487 + for_each_ufs_tx_lane(ufs, i) { 1488 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0xAA, i), 1489 + DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate)); 1490 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x8F, i), 0x3F); 1491 + } 1492 + 1493 + for_each_ufs_rx_lane(ufs, i) { 1494 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x12, i), 1495 + DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate)); 1496 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x5C, i), 0x38); 1497 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x0F, i), 0x0); 1498 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x65, i), 0x1); 1499 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x69, i), 0x1); 1500 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x21, i), 0x0); 1501 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x22, i), 0x0); 1502 + } 1503 + 1504 + ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0); 1505 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_AUTOMODE_THLD), 0x4E20); 1506 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OPTION_SUITE), 0x2e820183); 1507 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0x0); 1508 + 1509 + exynos_ufs_establish_connt(ufs); 1510 + 1511 + return 0; 1512 + } 1513 + 1514 + static int fsd_ufs_post_link(struct exynos_ufs *ufs) 1515 + { 1516 + int i; 1517 + struct ufs_hba *hba = ufs->hba; 1518 + u32 hw_cap_min_tactivate; 1519 + u32 peer_rx_min_actv_time_cap; 1520 + u32 max_rx_hibern8_time_cap; 1521 + 1522 + ufshcd_dme_get(hba, UIC_ARG_MIB_SEL(0x8F, 4), 1523 + &hw_cap_min_tactivate); /* HW Capability of MIN_TACTIVATE */ 1524 + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TACTIVATE), 1525 + &peer_rx_min_actv_time_cap); /* PA_TActivate */ 1526 + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_HIBERN8TIME), 1527 + &max_rx_hibern8_time_cap); /* PA_Hibern8Time */ 1528 + 1529 + if (peer_rx_min_actv_time_cap >= hw_cap_min_tactivate) 1530 + ufshcd_dme_peer_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 1531 + peer_rx_min_actv_time_cap + 1); 1532 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), max_rx_hibern8_time_cap + 1); 1533 + 1534 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), 0x01); 1535 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SAVECONFIGTIME), 0xFA); 1536 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), 0x00); 1537 + 1538 + ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40); 1539 + 1540 + for_each_ufs_rx_lane(ufs, i) { 1541 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x35, i), 0x05); 1542 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x73, i), 0x01); 1543 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x41, i), 0x02); 1544 + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x42, i), 0xAC); 1545 + } 1546 + 1547 + ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0); 1548 + 1549 + return 0; 1550 + } 1551 + 1552 + static int fsd_ufs_pre_pwr_change(struct exynos_ufs *ufs, 1553 + struct ufs_pa_layer_attr *pwr) 1554 + { 1555 + struct ufs_hba *hba = ufs->hba; 1556 + 1557 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), 0x1); 1558 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), 0x1); 1559 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), 12000); 1560 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), 32000); 1561 + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), 16000); 1562 + 1563 + unipro_writel(ufs, 12000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER0); 1564 + unipro_writel(ufs, 32000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER1); 1565 + unipro_writel(ufs, 16000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER2); 1566 + 1567 + return 0; 1568 + } 1569 + 1481 1570 static struct ufs_hba_variant_ops ufs_hba_exynos_ops = { 1482 1571 .name = "exynos_ufs", 1483 1572 .init = exynos_ufs_init, ··· 1693 1596 .post_pwr_change = exynos7_ufs_post_pwr_change, 1694 1597 }; 1695 1598 1599 + static struct exynos_ufs_uic_attr fsd_uic_attr = { 1600 + .tx_trailingclks = 0x10, 1601 + .tx_dif_p_nsec = 3000000, /* unit: ns */ 1602 + .tx_dif_n_nsec = 1000000, /* unit: ns */ 1603 + .tx_high_z_cnt_nsec = 20000, /* unit: ns */ 1604 + .tx_base_unit_nsec = 100000, /* unit: ns */ 1605 + .tx_gran_unit_nsec = 4000, /* unit: ns */ 1606 + .tx_sleep_cnt = 1000, /* unit: ns */ 1607 + .tx_min_activatetime = 0xa, 1608 + .rx_filler_enable = 0x2, 1609 + .rx_dif_p_nsec = 1000000, /* unit: ns */ 1610 + .rx_hibern8_wait_nsec = 4000000, /* unit: ns */ 1611 + .rx_base_unit_nsec = 100000, /* unit: ns */ 1612 + .rx_gran_unit_nsec = 4000, /* unit: ns */ 1613 + .rx_sleep_cnt = 1280, /* unit: ns */ 1614 + .rx_stall_cnt = 320, /* unit: ns */ 1615 + .rx_hs_g1_sync_len_cap = SYNC_LEN_COARSE(0xf), 1616 + .rx_hs_g2_sync_len_cap = SYNC_LEN_COARSE(0xf), 1617 + .rx_hs_g3_sync_len_cap = SYNC_LEN_COARSE(0xf), 1618 + .rx_hs_g1_prep_sync_len_cap = PREP_LEN(0xf), 1619 + .rx_hs_g2_prep_sync_len_cap = PREP_LEN(0xf), 1620 + .rx_hs_g3_prep_sync_len_cap = PREP_LEN(0xf), 1621 + .pa_dbg_option_suite = 0x2E820183, 1622 + }; 1623 + 1624 + struct exynos_ufs_drv_data fsd_ufs_drvs = { 1625 + .uic_attr = &fsd_uic_attr, 1626 + .quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN | 1627 + UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR | 1628 + UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR | 1629 + UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING | 1630 + UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR, 1631 + .opts = EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL | 1632 + EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL | 1633 + EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR | 1634 + EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX, 1635 + .pre_link = fsd_ufs_pre_link, 1636 + .post_link = fsd_ufs_post_link, 1637 + .pre_pwr_change = fsd_ufs_pre_pwr_change, 1638 + }; 1639 + 1696 1640 static const struct of_device_id exynos_ufs_of_match[] = { 1697 1641 { .compatible = "samsung,exynos7-ufs", 1698 1642 .data = &exynos_ufs_drvs }, ··· 1741 1603 .data = &exynosauto_ufs_drvs }, 1742 1604 { .compatible = "samsung,exynosautov9-ufs-vh", 1743 1605 .data = &exynosauto_ufs_vh_drvs }, 1606 + { .compatible = "tesla,fsd-ufs", 1607 + .data = &fsd_ufs_drvs }, 1744 1608 {}, 1745 1609 }; 1746 1610
+1
drivers/ufs/host/ufs-exynos.h
··· 22 22 #define PA_DBG_RXPHY_CFGUPDT 0x9519 23 23 #define PA_DBG_MODE 0x9529 24 24 #define PA_DBG_SKIP_RESET_PHY 0x9539 25 + #define PA_DBG_AUTOMODE_THLD 0x9536 25 26 #define PA_DBG_OV_TM 0x9540 26 27 #define PA_DBG_SKIP_LINE_RESET 0x9541 27 28 #define PA_DBG_LINE_RESET_REQ 0x9543