mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 12:35:52 +02:00
Merge patch series "UFS cleanups and enhancements to ufs-exynos for gs101"
Peter Griffin <peter.griffin@linaro.org> 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/20241002201555.3332138-3-peter.griffin@linaro.org/T/ regards, Peter Link: https://lore.kernel.org/r/20241031150033.3440894-1-peter.griffin@linaro.org Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
commit
b795a4a190
|
|
@ -23816,7 +23816,9 @@ F: drivers/ufs/host/*dwc*
|
|||
|
||||
UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER EXYNOS HOOKS
|
||||
M: Alim Akhtar <alim.akhtar@samsung.com>
|
||||
R: Peter Griffin <peter.griffin@linaro.org>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
L: linux-samsung-soc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/ufs/host/ufs-exynos*
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@
|
|||
#define HCI_UNIPRO_APB_CLK_CTRL 0x68
|
||||
#define UNIPRO_APB_CLK(v, x) (((v) & ~0xF) | ((x) & 0xF))
|
||||
#define HCI_AXIDMA_RWDATA_BURST_LEN 0x6C
|
||||
#define WLU_EN BIT(31)
|
||||
#define WLU_BURST_LEN(x) ((x) << 27 | ((x) & 0xF))
|
||||
#define HCI_GPIO_OUT 0x70
|
||||
#define HCI_ERR_EN_PA_LAYER 0x78
|
||||
#define HCI_ERR_EN_DL_LAYER 0x7C
|
||||
|
|
@ -74,6 +76,10 @@
|
|||
#define CLK_CTRL_EN_MASK (REFCLK_CTRL_EN |\
|
||||
UNIPRO_PCLK_CTRL_EN |\
|
||||
UNIPRO_MCLK_CTRL_EN)
|
||||
|
||||
#define HCI_IOP_ACG_DISABLE 0x100
|
||||
#define HCI_IOP_ACG_DISABLE_EN BIT(0)
|
||||
|
||||
/* Device fatal error */
|
||||
#define DFES_ERR_EN BIT(31)
|
||||
#define DFES_DEF_L2_ERRS (UIC_DATA_LINK_LAYER_ERROR_RX_BUF_OF |\
|
||||
|
|
@ -198,15 +204,8 @@ static inline void exynos_ufs_ungate_clks(struct exynos_ufs *ufs)
|
|||
exynos_ufs_ctrl_clkstop(ufs, false);
|
||||
}
|
||||
|
||||
static int exynos7_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
|
||||
static int exynos_ufs_shareability(struct exynos_ufs *ufs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
|
||||
{
|
||||
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
|
||||
|
||||
/* IO Coherency setting */
|
||||
if (ufs->sysreg) {
|
||||
return regmap_update_bits(ufs->sysreg,
|
||||
|
|
@ -214,11 +213,32 @@ static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
|
|||
UFS_SHARABLE, UFS_SHARABLE);
|
||||
}
|
||||
|
||||
attr->tx_dif_p_nsec = 3200000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gs101_ufs_drv_init(struct exynos_ufs *ufs)
|
||||
{
|
||||
struct ufs_hba *hba = ufs->hba;
|
||||
u32 reg;
|
||||
|
||||
/* Enable WriteBooster */
|
||||
hba->caps |= UFSHCD_CAP_WB_EN;
|
||||
|
||||
/* Enable clock gating and hibern8 */
|
||||
hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
|
||||
|
||||
/* set ACG to be controlled by UFS_ACG_DISABLE */
|
||||
reg = hci_readl(ufs, HCI_IOP_ACG_DISABLE);
|
||||
hci_writel(ufs, reg & (~HCI_IOP_ACG_DISABLE_EN), HCI_IOP_ACG_DISABLE);
|
||||
|
||||
return exynos_ufs_shareability(ufs);
|
||||
}
|
||||
|
||||
static int exynosauto_ufs_drv_init(struct exynos_ufs *ufs)
|
||||
{
|
||||
return exynos_ufs_shareability(ufs);
|
||||
}
|
||||
|
||||
static int exynosauto_ufs_post_hce_enable(struct exynos_ufs *ufs)
|
||||
{
|
||||
struct ufs_hba *hba = ufs->hba;
|
||||
|
|
@ -546,6 +566,9 @@ static void exynos_ufs_specify_phy_time_attr(struct exynos_ufs *ufs)
|
|||
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
|
||||
struct ufs_phy_time_cfg *t_cfg = &ufs->t_cfg;
|
||||
|
||||
if (ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR)
|
||||
return;
|
||||
|
||||
t_cfg->tx_linereset_p =
|
||||
exynos_ufs_calc_time_cntr(ufs, attr->tx_dif_p_nsec);
|
||||
t_cfg->tx_linereset_n =
|
||||
|
|
@ -724,6 +747,9 @@ static void exynos_ufs_config_smu(struct exynos_ufs *ufs)
|
|||
{
|
||||
u32 reg, val;
|
||||
|
||||
if (ufs->opts & EXYNOS_UFS_OPT_UFSPR_SECURE)
|
||||
return;
|
||||
|
||||
exynos_ufs_disable_auto_ctrl_hcc_save(ufs, &val);
|
||||
|
||||
/* make encryption disabled by default */
|
||||
|
|
@ -771,6 +797,21 @@ static void exynos_ufs_config_sync_pattern_mask(struct exynos_ufs *ufs,
|
|||
exynos_ufs_disable_ov_tm(hba);
|
||||
}
|
||||
|
||||
#define UFS_HW_VER_MAJOR_MASK GENMASK(15, 8)
|
||||
|
||||
static u32 exynos_ufs_get_hs_gear(struct ufs_hba *hba)
|
||||
{
|
||||
u8 major;
|
||||
|
||||
major = FIELD_GET(UFS_HW_VER_MAJOR_MASK, hba->ufs_version);
|
||||
|
||||
if (major >= 3)
|
||||
return UFS_HS_G4;
|
||||
|
||||
/* Default is HS-G3 */
|
||||
return UFS_HS_G3;
|
||||
}
|
||||
|
||||
static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
|
||||
struct ufs_pa_layer_attr *dev_max_params,
|
||||
struct ufs_pa_layer_attr *dev_req_params)
|
||||
|
|
@ -788,6 +829,10 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba,
|
|||
|
||||
ufshcd_init_host_params(&host_params);
|
||||
|
||||
/* This driver only support symmetric gear setting e.g. hs_tx_gear == hs_rx_gear */
|
||||
host_params.hs_tx_gear = exynos_ufs_get_hs_gear(hba);
|
||||
host_params.hs_rx_gear = exynos_ufs_get_hs_gear(hba);
|
||||
|
||||
ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to determine capabilities\n", __func__);
|
||||
|
|
@ -1429,7 +1474,7 @@ static int exynos_ufs_init(struct ufs_hba *hba)
|
|||
exynos_ufs_fmp_init(hba, ufs);
|
||||
|
||||
if (ufs->drv_data->drv_init) {
|
||||
ret = ufs->drv_data->drv_init(dev, ufs);
|
||||
ret = ufs->drv_data->drv_init(ufs);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init drv-data\n");
|
||||
goto out;
|
||||
|
|
@ -1440,8 +1485,8 @@ static int exynos_ufs_init(struct ufs_hba *hba)
|
|||
if (ret)
|
||||
goto out;
|
||||
exynos_ufs_specify_phy_time_attr(ufs);
|
||||
if (!(ufs->opts & EXYNOS_UFS_OPT_UFSPR_SECURE))
|
||||
exynos_ufs_config_smu(ufs);
|
||||
|
||||
exynos_ufs_config_smu(ufs);
|
||||
|
||||
hba->host->dma_alignment = DATA_UNIT_SIZE - 1;
|
||||
return 0;
|
||||
|
|
@ -1484,12 +1529,12 @@ static void exynos_ufs_dev_hw_reset(struct ufs_hba *hba)
|
|||
hci_writel(ufs, 1 << 0, HCI_GPIO_OUT);
|
||||
}
|
||||
|
||||
static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter)
|
||||
static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
|
||||
{
|
||||
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
|
||||
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
|
||||
|
||||
if (!enter) {
|
||||
if (cmd == UIC_CMD_DME_HIBER_EXIT) {
|
||||
if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL)
|
||||
exynos_ufs_disable_auto_ctrl_hcc(ufs);
|
||||
exynos_ufs_ungate_clks(ufs);
|
||||
|
|
@ -1517,30 +1562,11 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, u8 enter)
|
|||
}
|
||||
}
|
||||
|
||||
static void exynos_ufs_post_hibern8(struct ufs_hba *hba, u8 enter)
|
||||
static void exynos_ufs_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd)
|
||||
{
|
||||
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
|
||||
|
||||
if (!enter) {
|
||||
u32 cur_mode = 0;
|
||||
u32 pwrmode;
|
||||
|
||||
if (ufshcd_is_hs_mode(&ufs->dev_req_params))
|
||||
pwrmode = FAST_MODE;
|
||||
else
|
||||
pwrmode = SLOW_MODE;
|
||||
|
||||
ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &cur_mode);
|
||||
if (cur_mode != (pwrmode << 4 | pwrmode)) {
|
||||
dev_warn(hba->dev, "%s: power mode change\n", __func__);
|
||||
hba->pwr_info.pwr_rx = (cur_mode >> 4) & 0xf;
|
||||
hba->pwr_info.pwr_tx = cur_mode & 0xf;
|
||||
ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info);
|
||||
}
|
||||
|
||||
if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB))
|
||||
exynos_ufs_establish_connt(ufs);
|
||||
} else {
|
||||
if (cmd == UIC_CMD_DME_HIBER_ENTER) {
|
||||
ufs->entry_hibern8_t = ktime_get();
|
||||
exynos_ufs_gate_clks(ufs);
|
||||
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,
|
|||
}
|
||||
|
||||
static void exynos_ufs_hibern8_notify(struct ufs_hba *hba,
|
||||
enum uic_cmd_dme enter,
|
||||
enum uic_cmd_dme cmd,
|
||||
enum ufs_notify_change_status notify)
|
||||
{
|
||||
switch ((u8)notify) {
|
||||
case PRE_CHANGE:
|
||||
exynos_ufs_pre_hibern8(hba, enter);
|
||||
exynos_ufs_pre_hibern8(hba, cmd);
|
||||
break;
|
||||
case POST_CHANGE:
|
||||
exynos_ufs_post_hibern8(hba, enter);
|
||||
exynos_ufs_post_hibern8(hba, cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1891,6 +1917,12 @@ static int gs101_ufs_post_link(struct exynos_ufs *ufs)
|
|||
{
|
||||
struct ufs_hba *hba = ufs->hba;
|
||||
|
||||
/*
|
||||
* Enable Write Line Unique. This field has to be 0x3
|
||||
* to support Write Line Unique transaction on gs101.
|
||||
*/
|
||||
hci_writel(ufs, WLU_EN | WLU_BURST_LEN(3), HCI_AXIDMA_RWDATA_BURST_LEN);
|
||||
|
||||
exynos_ufs_enable_dbg_mode(hba);
|
||||
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SAVECONFIGTIME), 0x3e8);
|
||||
exynos_ufs_disable_dbg_mode(hba);
|
||||
|
|
@ -2036,7 +2068,6 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = {
|
|||
EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX |
|
||||
EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB |
|
||||
EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER,
|
||||
.drv_init = exynos7_ufs_drv_init,
|
||||
.pre_link = exynos7_ufs_pre_link,
|
||||
.post_link = exynos7_ufs_post_link,
|
||||
.pre_pwr_change = exynos7_ufs_pre_pwr_change,
|
||||
|
|
@ -2045,26 +2076,6 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = {
|
|||
|
||||
static struct exynos_ufs_uic_attr gs101_uic_attr = {
|
||||
.tx_trailingclks = 0xff,
|
||||
.tx_dif_p_nsec = 3000000, /* unit: ns */
|
||||
.tx_dif_n_nsec = 1000000, /* unit: ns */
|
||||
.tx_high_z_cnt_nsec = 20000, /* unit: ns */
|
||||
.tx_base_unit_nsec = 100000, /* unit: ns */
|
||||
.tx_gran_unit_nsec = 4000, /* unit: ns */
|
||||
.tx_sleep_cnt = 1000, /* unit: ns */
|
||||
.tx_min_activatetime = 0xa,
|
||||
.rx_filler_enable = 0x2,
|
||||
.rx_dif_p_nsec = 1000000, /* unit: ns */
|
||||
.rx_hibern8_wait_nsec = 4000000, /* unit: ns */
|
||||
.rx_base_unit_nsec = 100000, /* unit: ns */
|
||||
.rx_gran_unit_nsec = 4000, /* unit: ns */
|
||||
.rx_sleep_cnt = 1280, /* unit: ns */
|
||||
.rx_stall_cnt = 320, /* unit: ns */
|
||||
.rx_hs_g1_sync_len_cap = SYNC_LEN_COARSE(0xf),
|
||||
.rx_hs_g2_sync_len_cap = SYNC_LEN_COARSE(0xf),
|
||||
.rx_hs_g3_sync_len_cap = SYNC_LEN_COARSE(0xf),
|
||||
.rx_hs_g1_prep_sync_len_cap = PREP_LEN(0xf),
|
||||
.rx_hs_g2_prep_sync_len_cap = PREP_LEN(0xf),
|
||||
.rx_hs_g3_prep_sync_len_cap = PREP_LEN(0xf),
|
||||
.pa_dbg_opt_suite1_val = 0x90913C1C,
|
||||
.pa_dbg_opt_suite1_off = PA_GS101_DBG_OPTION_SUITE1,
|
||||
.pa_dbg_opt_suite2_val = 0xE01C115F,
|
||||
|
|
@ -2122,11 +2133,10 @@ static const struct exynos_ufs_drv_data gs101_ufs_drvs = {
|
|||
UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
|
||||
UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL |
|
||||
UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING,
|
||||
.opts = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
|
||||
EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
|
||||
.opts = EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
|
||||
EXYNOS_UFS_OPT_UFSPR_SECURE |
|
||||
EXYNOS_UFS_OPT_TIMER_TICK_SELECT,
|
||||
.drv_init = exynosauto_ufs_drv_init,
|
||||
.drv_init = gs101_ufs_drv_init,
|
||||
.pre_link = gs101_ufs_pre_link,
|
||||
.post_link = gs101_ufs_post_link,
|
||||
.pre_pwr_change = gs101_ufs_pre_pwr_change,
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ struct exynos_ufs_drv_data {
|
|||
unsigned int quirks;
|
||||
unsigned int opts;
|
||||
/* SoC's specific operations */
|
||||
int (*drv_init)(struct device *dev, struct exynos_ufs *ufs);
|
||||
int (*drv_init)(struct exynos_ufs *ufs);
|
||||
int (*pre_link)(struct exynos_ufs *ufs);
|
||||
int (*post_link)(struct exynos_ufs *ufs);
|
||||
int (*pre_pwr_change)(struct exynos_ufs *ufs,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user