Skip to content

Commit b795a4a

Browse files
Merge patch series "UFS cleanups and enhancements to ufs-exynos for gs101"
Peter Griffin <[email protected]> says: Hi folks, This series provides a few cleanups, bug fixes and feature enhancements for the ufs-exynos driver, particularly for gs101 SoC. Regarding cleanup we remove some unused phy attribute data that isn't required when EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR is not set. Regarding bug fixes the check for EXYNOS_UFS_OPT_UFSPR_SECURE is moved inside exynos_ufs_config_smu() which fixes a Serror in the resume path for gs101. Regarding feature enhancements: * Gear 4 is enabled which has higher speeds and better power management. * WriteBooster capability is enabled for gs101 which increases write performance. * Clock gating and hibern8 capabilities are enabled for gs101. This leads to a significantly cooler phone when running the upstream kernel on Pixel 6. Approximately 10 degrees cooler after 20 minutes at a shell prompt. * AXI bus on gs101 is correctly configured for write line unique transactions * ACG is set to be controlled by UFS_ACG_DISABLE for gs101 Additionally in v3 I've added 2 minor cleanup patches from Tudor and also an update to MAINTAINERS to add myself as a reviewer and the linux-samsung-soc list. Note: In v1 I mentioned the phy hibern8 series in [1] that is still under discussion however further testing reveals hibern8 feature still works without the additional UFS phy register writes done in [1]. So this series can be merged as is and has no runtime dependencies on [1] to be functional. [1] https://lore.kernel.org/linux-arm-kernel/[email protected]/T/ regards, Peter Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
2 parents b92e593 + d49df3d commit b795a4a

File tree

3 files changed

+76
-64
lines changed

3 files changed

+76
-64
lines changed

MAINTAINERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23816,7 +23816,9 @@ F: drivers/ufs/host/*dwc*
2381623816

2381723817
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER EXYNOS HOOKS
2381823818
M: Alim Akhtar <[email protected]>
23819+
R: Peter Griffin <[email protected]>
2381923820
23821+
2382023822
S: Maintained
2382123823
F: drivers/ufs/host/ufs-exynos*
2382223824

drivers/ufs/host/ufs-exynos.c

Lines changed: 73 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
#define HCI_UNIPRO_APB_CLK_CTRL 0x68
4949
#define UNIPRO_APB_CLK(v, x) (((v) & ~0xF) | ((x) & 0xF))
5050
#define HCI_AXIDMA_RWDATA_BURST_LEN 0x6C
51+
#define WLU_EN BIT(31)
52+
#define WLU_BURST_LEN(x) ((x) << 27 | ((x) & 0xF))
5153
#define HCI_GPIO_OUT 0x70
5254
#define HCI_ERR_EN_PA_LAYER 0x78
5355
#define HCI_ERR_EN_DL_LAYER 0x7C
@@ -74,6 +76,10 @@
7476
#define CLK_CTRL_EN_MASK (REFCLK_CTRL_EN |\
7577
UNIPRO_PCLK_CTRL_EN |\
7678
UNIPRO_MCLK_CTRL_EN)
79+
80+
#define HCI_IOP_ACG_DISABLE 0x100
81+
#define HCI_IOP_ACG_DISABLE_EN BIT(0)
82+
7783
/* Device fatal error */
7884
#define DFES_ERR_EN BIT(31)
7985
#define DFES_DEF_L2_ERRS (UIC_DATA_LINK_LAYER_ERROR_RX_BUF_OF |\
@@ -198,27 +204,41 @@ static inline void exynos_ufs_ungate_clks(struct exynos_ufs *ufs)
198204
exynos_ufs_ctrl_clkstop(ufs, false);
199205
}
200206

201-
static int exynos7_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
202-
{
203-
return 0;
204-
}
205-
206-
static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
207+
static int exynos_ufs_shareability(struct exynos_ufs *ufs)
207208
{
208-
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
209-
210209
/* IO Coherency setting */
211210
if (ufs->sysreg) {
212211
return regmap_update_bits(ufs->sysreg,
213212
ufs->shareability_reg_offset,
214213
UFS_SHARABLE, UFS_SHARABLE);
215214
}
216215

217-
attr->tx_dif_p_nsec = 3200000;
218-
219216
return 0;
220217
}
221218

219+
static int gs101_ufs_drv_init(struct exynos_ufs *ufs)
220+
{
221+
struct ufs_hba *hba = ufs->hba;
222+
u32 reg;
223+
224+
/* Enable WriteBooster */
225+
hba->caps |= UFSHCD_CAP_WB_EN;
226+
227+
/* Enable clock gating and hibern8 */
228+
hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
229+
230+
/* set ACG to be controlled by UFS_ACG_DISABLE */
231+
reg = hci_readl(ufs, HCI_IOP_ACG_DISABLE);
232+
hci_writel(ufs, reg & (~HCI_IOP_ACG_DISABLE_EN), HCI_IOP_ACG_DISABLE);
233+
234+
return exynos_ufs_shareability(ufs);
235+
}
236+
237+
static int exynosauto_ufs_drv_init(struct exynos_ufs *ufs)
238+
{
239+
return exynos_ufs_shareability(ufs);
240+
}
241+
222242
static int exynosauto_ufs_post_hce_enable(struct exynos_ufs *ufs)
223243
{
224244
struct ufs_hba *hba = ufs->hba;
@@ -546,6 +566,9 @@ static void exynos_ufs_specify_phy_time_attr(struct exynos_ufs *ufs)
546566
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
547567
struct ufs_phy_time_cfg *t_cfg = &ufs->t_cfg;
548568

569+
if (ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR)
570+
return;
571+
549572
t_cfg->tx_linereset_p =
550573
exynos_ufs_calc_time_cntr(ufs, attr->tx_dif_p_nsec);
551574
t_cfg->tx_linereset_n =
@@ -724,6 +747,9 @@ static void exynos_ufs_config_smu(struct exynos_ufs *ufs)
724747
{
725748
u32 reg, val;
726749

750+
if (ufs->opts & EXYNOS_UFS_OPT_UFSPR_SECURE)
751+
return;
752+
727753
exynos_ufs_disable_auto_ctrl_hcc_save(ufs, &val);
728754

729755
/* make encryption disabled by default */
@@ -771,6 +797,21 @@ static void exynos_ufs_config_sync_pattern_mask(struct exynos_ufs *ufs,
771797
exynos_ufs_disable_ov_tm(hba);
772798
}
773799

800+
#define UFS_HW_VER_MAJOR_MASK GENMASK(15, 8)
801+
802+
static u32 exynos_ufs_get_hs_gear(struct ufs_hba *hba)
803+
{
804+
u8 major;
805+
806+
major = FIELD_GET(UFS_HW_VER_MAJOR_MASK, hba->ufs_version);
807+
808+
if (major >= 3)
809+
return UFS_HS_G4;
810+
811+
/* Default is HS-G3 */
812+
return UFS_HS_G3;
813+
}
814+
774815
static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
775816
struct ufs_pa_layer_attr *dev_max_params,
776817
struct ufs_pa_layer_attr *dev_req_params)
@@ -788,6 +829,10 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
788829

789830
ufshcd_init_host_params(&host_params);
790831

832+
/* This driver only support symmetric gear setting e.g. hs_tx_gear == hs_rx_gear */
833+
host_params.hs_tx_gear = exynos_ufs_get_hs_gear(hba);
834+
host_params.hs_rx_gear = exynos_ufs_get_hs_gear(hba);
835+
791836
ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
792837
if (ret) {
793838
pr_err("%s: failed to determine capabilities\n", __func__);
@@ -1429,7 +1474,7 @@ static int exynos_ufs_init(struct ufs_hba *hba)
14291474
exynos_ufs_fmp_init(hba, ufs);
14301475

14311476
if (ufs->drv_data->drv_init) {
1432-
ret = ufs->drv_data->drv_init(dev, ufs);
1477+
ret = ufs->drv_data->drv_init(ufs);
14331478
if (ret) {
14341479
dev_err(dev, "failed to init drv-data\n");
14351480
goto out;
@@ -1440,8 +1485,8 @@ static int exynos_ufs_init(struct ufs_hba *hba)
14401485
if (ret)
14411486
goto out;
14421487
exynos_ufs_specify_phy_time_attr(ufs);
1443-
if (!(ufs->opts & EXYNOS_UFS_OPT_UFSPR_SECURE))
1444-
exynos_ufs_config_smu(ufs);
1488+
1489+
exynos_ufs_config_smu(ufs);
14451490

14461491
hba->host->dma_alignment = DATA_UNIT_SIZE - 1;
14471492
return 0;
@@ -1484,12 +1529,12 @@ static void exynos_ufs_dev_hw_reset(struct ufs_hba *hba)
14841529
hci_writel(ufs, 1 << 0, HCI_GPIO_OUT);
14851530
}
14861531

1487-
static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter)
1532+
static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
14881533
{
14891534
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
14901535
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
14911536

1492-
if (!enter) {
1537+
if (cmd == UIC_CMD_DME_HIBER_EXIT) {
14931538
if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL)
14941539
exynos_ufs_disable_auto_ctrl_hcc(ufs);
14951540
exynos_ufs_ungate_clks(ufs);
@@ -1517,30 +1562,11 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter)
15171562
}
15181563
}
15191564

1520-
static void exynos_ufs_post_hibern8(struct ufs_hba *hba, u8 enter)
1565+
static void exynos_ufs_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
15211566
{
15221567
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
15231568

1524-
if (!enter) {
1525-
u32 cur_mode = 0;
1526-
u32 pwrmode;
1527-
1528-
if (ufshcd_is_hs_mode(&ufs->dev_req_params))
1529-
pwrmode = FAST_MODE;
1530-
else
1531-
pwrmode = SLOW_MODE;
1532-
1533-
ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &cur_mode);
1534-
if (cur_mode != (pwrmode << 4 | pwrmode)) {
1535-
dev_warn(hba->dev, "%s: power mode change\n", __func__);
1536-
hba->pwr_info.pwr_rx = (cur_mode >> 4) & 0xf;
1537-
hba->pwr_info.pwr_tx = cur_mode & 0xf;
1538-
ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info);
1539-
}
1540-
1541-
if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB))
1542-
exynos_ufs_establish_connt(ufs);
1543-
} else {
1569+
if (cmd == UIC_CMD_DME_HIBER_ENTER) {
15441570
ufs->entry_hibern8_t = ktime_get();
15451571
exynos_ufs_gate_clks(ufs);
15461572
if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL)
@@ -1627,15 +1653,15 @@ static int exynos_ufs_pwr_change_notify(struct ufs_hba *hba,
16271653
}
16281654

16291655
static void exynos_ufs_hibern8_notify(struct ufs_hba *hba,
1630-
enum uic_cmd_dme enter,
1656+
enum uic_cmd_dme cmd,
16311657
enum ufs_notify_change_status notify)
16321658
{
16331659
switch ((u8)notify) {
16341660
case PRE_CHANGE:
1635-
exynos_ufs_pre_hibern8(hba, enter);
1661+
exynos_ufs_pre_hibern8(hba, cmd);
16361662
break;
16371663
case POST_CHANGE:
1638-
exynos_ufs_post_hibern8(hba, enter);
1664+
exynos_ufs_post_hibern8(hba, cmd);
16391665
break;
16401666
}
16411667
}
@@ -1891,6 +1917,12 @@ static int gs101_ufs_post_link(struct exynos_ufs *ufs)
18911917
{
18921918
struct ufs_hba *hba = ufs->hba;
18931919

1920+
/*
1921+
* Enable Write Line Unique. This field has to be 0x3
1922+
* to support Write Line Unique transaction on gs101.
1923+
*/
1924+
hci_writel(ufs, WLU_EN | WLU_BURST_LEN(3), HCI_AXIDMA_RWDATA_BURST_LEN);
1925+
18941926
exynos_ufs_enable_dbg_mode(hba);
18951927
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SAVECONFIGTIME), 0x3e8);
18961928
exynos_ufs_disable_dbg_mode(hba);
@@ -2036,7 +2068,6 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = {
20362068
EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX |
20372069
EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB |
20382070
EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER,
2039-
.drv_init = exynos7_ufs_drv_init,
20402071
.pre_link = exynos7_ufs_pre_link,
20412072
.post_link = exynos7_ufs_post_link,
20422073
.pre_pwr_change = exynos7_ufs_pre_pwr_change,
@@ -2045,26 +2076,6 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = {
20452076

20462077
static struct exynos_ufs_uic_attr gs101_uic_attr = {
20472078
.tx_trailingclks = 0xff,
2048-
.tx_dif_p_nsec = 3000000, /* unit: ns */
2049-
.tx_dif_n_nsec = 1000000, /* unit: ns */
2050-
.tx_high_z_cnt_nsec = 20000, /* unit: ns */
2051-
.tx_base_unit_nsec = 100000, /* unit: ns */
2052-
.tx_gran_unit_nsec = 4000, /* unit: ns */
2053-
.tx_sleep_cnt = 1000, /* unit: ns */
2054-
.tx_min_activatetime = 0xa,
2055-
.rx_filler_enable = 0x2,
2056-
.rx_dif_p_nsec = 1000000, /* unit: ns */
2057-
.rx_hibern8_wait_nsec = 4000000, /* unit: ns */
2058-
.rx_base_unit_nsec = 100000, /* unit: ns */
2059-
.rx_gran_unit_nsec = 4000, /* unit: ns */
2060-
.rx_sleep_cnt = 1280, /* unit: ns */
2061-
.rx_stall_cnt = 320, /* unit: ns */
2062-
.rx_hs_g1_sync_len_cap = SYNC_LEN_COARSE(0xf),
2063-
.rx_hs_g2_sync_len_cap = SYNC_LEN_COARSE(0xf),
2064-
.rx_hs_g3_sync_len_cap = SYNC_LEN_COARSE(0xf),
2065-
.rx_hs_g1_prep_sync_len_cap = PREP_LEN(0xf),
2066-
.rx_hs_g2_prep_sync_len_cap = PREP_LEN(0xf),
2067-
.rx_hs_g3_prep_sync_len_cap = PREP_LEN(0xf),
20682079
.pa_dbg_opt_suite1_val = 0x90913C1C,
20692080
.pa_dbg_opt_suite1_off = PA_GS101_DBG_OPTION_SUITE1,
20702081
.pa_dbg_opt_suite2_val = 0xE01C115F,
@@ -2122,11 +2133,10 @@ static const struct exynos_ufs_drv_data gs101_ufs_drvs = {
21222133
UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
21232134
UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL |
21242135
UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING,
2125-
.opts = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
2126-
EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
2136+
.opts = EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
21272137
EXYNOS_UFS_OPT_UFSPR_SECURE |
21282138
EXYNOS_UFS_OPT_TIMER_TICK_SELECT,
2129-
.drv_init = exynosauto_ufs_drv_init,
2139+
.drv_init = gs101_ufs_drv_init,
21302140
.pre_link = gs101_ufs_pre_link,
21312141
.post_link = gs101_ufs_post_link,
21322142
.pre_pwr_change = gs101_ufs_pre_pwr_change,

drivers/ufs/host/ufs-exynos.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ struct exynos_ufs_drv_data {
182182
unsigned int quirks;
183183
unsigned int opts;
184184
/* SoC's specific operations */
185-
int (*drv_init)(struct device *dev, struct exynos_ufs *ufs);
185+
int (*drv_init)(struct exynos_ufs *ufs);
186186
int (*pre_link)(struct exynos_ufs *ufs);
187187
int (*post_link)(struct exynos_ufs *ufs);
188188
int (*pre_pwr_change)(struct exynos_ufs *ufs,

0 commit comments

Comments
 (0)