Skip to content

Commit

Permalink
Merge patch series "ufs-exynos stability fixes for gs101"
Browse files Browse the repository at this point in the history
Peter Griffin <peter.griffin@linaro.org> says:

Hi folks,

This series fixes several stability issues with the upstream ufs-exynos
driver, specifically for the gs101 SoC found in Pixel 6.

The main fix is regarding the IO cache coherency setting and ensuring
that it is correctly applied depending on if the dma-coherent property
is specified in device tree. This fixes the UFS stability issues on gs101
and I would imagine will also fix issues on exynosauto platform that
seems to have similar iocc shareability bits.

Additionally the phy reference counting is fixed which allows module
load/unload to work reliably and keeps the phy state machine in sync
with the controller glue driver.

regards,

Peter

Link: https://lore.kernel.org/r/20250319-exynos-ufs-stability-fixes-v2-0-96722cc2ba1b@linaro.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Martin K. Petersen committed Apr 3, 2025
2 parents 72eea84 + cd4c002 commit 8a65b75
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 23 deletions.
85 changes: 63 additions & 22 deletions drivers/ufs/host/ufs-exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* Exynos's Vendor specific registers for UFSHCI
*/
#define HCI_TXPRDT_ENTRY_SIZE 0x00
#define PRDT_PREFECT_EN BIT(31)
#define PRDT_PREFETCH_EN BIT(31)
#define HCI_RXPRDT_ENTRY_SIZE 0x04
#define HCI_1US_TO_CNT_VAL 0x0C
#define CNT_VAL_1US_MASK 0x3FF
Expand Down Expand Up @@ -92,11 +92,16 @@
UIC_TRANSPORT_NO_CONNECTION_RX |\
UIC_TRANSPORT_BAD_TC)

/* FSYS UFS Shareability */
#define UFS_WR_SHARABLE BIT(2)
#define UFS_RD_SHARABLE BIT(1)
#define UFS_SHARABLE (UFS_WR_SHARABLE | UFS_RD_SHARABLE)
#define UFS_SHAREABILITY_OFFSET 0x710
/* UFS Shareability */
#define UFS_EXYNOSAUTO_WR_SHARABLE BIT(2)
#define UFS_EXYNOSAUTO_RD_SHARABLE BIT(1)
#define UFS_EXYNOSAUTO_SHARABLE (UFS_EXYNOSAUTO_WR_SHARABLE | \
UFS_EXYNOSAUTO_RD_SHARABLE)
#define UFS_GS101_WR_SHARABLE BIT(1)
#define UFS_GS101_RD_SHARABLE BIT(0)
#define UFS_GS101_SHARABLE (UFS_GS101_WR_SHARABLE | \
UFS_GS101_RD_SHARABLE)
#define UFS_SHAREABILITY_OFFSET 0x710

/* Multi-host registers */
#define MHCTRL 0xC4
Expand Down Expand Up @@ -209,8 +214,8 @@ static int exynos_ufs_shareability(struct exynos_ufs *ufs)
/* IO Coherency setting */
if (ufs->sysreg) {
return regmap_update_bits(ufs->sysreg,
ufs->shareability_reg_offset,
UFS_SHARABLE, UFS_SHARABLE);
ufs->iocc_offset,
ufs->iocc_mask, ufs->iocc_val);
}

return 0;
Expand Down Expand Up @@ -957,6 +962,12 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs)
}

phy_set_bus_width(generic_phy, ufs->avail_ln_rx);

if (generic_phy->power_count) {
phy_power_off(generic_phy);
phy_exit(generic_phy);
}

ret = phy_init(generic_phy);
if (ret) {
dev_err(hba->dev, "%s: phy init failed, ret = %d\n",
Expand Down Expand Up @@ -1049,21 +1060,21 @@ static int exynos_ufs_pre_link(struct ufs_hba *hba)
exynos_ufs_config_intr(ufs, DFES_DEF_L4_ERRS, UNIPRO_L4);
exynos_ufs_set_unipro_pclk_div(ufs);

exynos_ufs_setup_clocks(hba, true, PRE_CHANGE);

/* unipro */
exynos_ufs_config_unipro(ufs);

if (ufs->drv_data->pre_link)
ufs->drv_data->pre_link(ufs);

/* m-phy */
exynos_ufs_phy_init(ufs);
if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR)) {
exynos_ufs_config_phy_time_attr(ufs);
exynos_ufs_config_phy_cap_attr(ufs);
}

exynos_ufs_setup_clocks(hba, true, PRE_CHANGE);

if (ufs->drv_data->pre_link)
ufs->drv_data->pre_link(ufs);

return 0;
}

Expand All @@ -1087,12 +1098,17 @@ static int exynos_ufs_post_link(struct ufs_hba *hba)
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
struct phy *generic_phy = ufs->phy;
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
u32 val = ilog2(DATA_UNIT_SIZE);

exynos_ufs_establish_connt(ufs);
exynos_ufs_fit_aggr_timeout(ufs);

hci_writel(ufs, 0xa, HCI_DATA_REORDER);
hci_writel(ufs, ilog2(DATA_UNIT_SIZE), HCI_TXPRDT_ENTRY_SIZE);

if (hba->caps & UFSHCD_CAP_CRYPTO)
val |= PRDT_PREFETCH_EN;
hci_writel(ufs, val, HCI_TXPRDT_ENTRY_SIZE);

hci_writel(ufs, ilog2(DATA_UNIT_SIZE), HCI_RXPRDT_ENTRY_SIZE);
hci_writel(ufs, (1 << hba->nutrs) - 1, HCI_UTRL_NEXUS_TYPE);
hci_writel(ufs, (1 << hba->nutmrs) - 1, HCI_UTMRL_NEXUS_TYPE);
Expand Down Expand Up @@ -1168,12 +1184,22 @@ static int exynos_ufs_parse_dt(struct device *dev, struct exynos_ufs *ufs)
ufs->sysreg = NULL;
else {
if (of_property_read_u32_index(np, "samsung,sysreg", 1,
&ufs->shareability_reg_offset)) {
&ufs->iocc_offset)) {
dev_warn(dev, "can't get an offset from sysreg. Set to default value\n");
ufs->shareability_reg_offset = UFS_SHAREABILITY_OFFSET;
ufs->iocc_offset = UFS_SHAREABILITY_OFFSET;
}
}

ufs->iocc_mask = ufs->drv_data->iocc_mask;
/*
* no 'dma-coherent' property means the descriptors are
* non-cacheable so iocc shareability should be disabled.
*/
if (of_dma_is_coherent(dev->of_node))
ufs->iocc_val = ufs->iocc_mask;
else
ufs->iocc_val = 0;

ufs->pclk_avail_min = PCLK_AVAIL_MIN;
ufs->pclk_avail_max = PCLK_AVAIL_MAX;

Expand Down Expand Up @@ -1496,6 +1522,14 @@ static int exynos_ufs_init(struct ufs_hba *hba)
return ret;
}

static void exynos_ufs_exit(struct ufs_hba *hba)
{
struct exynos_ufs *ufs = ufshcd_get_variant(hba);

phy_power_off(ufs->phy);
phy_exit(ufs->phy);
}

static int exynos_ufs_host_reset(struct ufs_hba *hba)
{
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
Expand Down Expand Up @@ -1666,6 +1700,12 @@ static void exynos_ufs_hibern8_notify(struct ufs_hba *hba,
}
}

static int gs101_ufs_suspend(struct exynos_ufs *ufs)
{
hci_writel(ufs, 0 << 0, HCI_GPIO_OUT);
return 0;
}

static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
enum ufs_notify_change_status status)
{
Expand All @@ -1674,6 +1714,9 @@ static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
if (status == PRE_CHANGE)
return 0;

if (ufs->drv_data->suspend)
ufs->drv_data->suspend(ufs);

if (!ufshcd_is_link_active(hba))
phy_power_off(ufs->phy);

Expand Down Expand Up @@ -1951,6 +1994,7 @@ static int gs101_ufs_pre_pwr_change(struct exynos_ufs *ufs,
static const struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
.name = "exynos_ufs",
.init = exynos_ufs_init,
.exit = exynos_ufs_exit,
.hce_enable_notify = exynos_ufs_hce_enable_notify,
.link_startup_notify = exynos_ufs_link_startup_notify,
.pwr_change_notify = exynos_ufs_pwr_change_notify,
Expand Down Expand Up @@ -1989,13 +2033,7 @@ static int exynos_ufs_probe(struct platform_device *pdev)

static void exynos_ufs_remove(struct platform_device *pdev)
{
struct ufs_hba *hba = platform_get_drvdata(pdev);
struct exynos_ufs *ufs = ufshcd_get_variant(hba);

ufshcd_pltfrm_remove(pdev);

phy_power_off(ufs->phy);
phy_exit(ufs->phy);
}

static struct exynos_ufs_uic_attr exynos7_uic_attr = {
Expand Down Expand Up @@ -2034,6 +2072,7 @@ static const struct exynos_ufs_drv_data exynosauto_ufs_drvs = {
.opts = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX,
.iocc_mask = UFS_EXYNOSAUTO_SHARABLE,
.drv_init = exynosauto_ufs_drv_init,
.post_hce_enable = exynosauto_ufs_post_hce_enable,
.pre_link = exynosauto_ufs_pre_link,
Expand Down Expand Up @@ -2135,10 +2174,12 @@ static const struct exynos_ufs_drv_data gs101_ufs_drvs = {
.opts = EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
EXYNOS_UFS_OPT_UFSPR_SECURE |
EXYNOS_UFS_OPT_TIMER_TICK_SELECT,
.iocc_mask = UFS_GS101_SHARABLE,
.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,
.suspend = gs101_ufs_suspend,
};

static const struct of_device_id exynos_ufs_of_match[] = {
Expand Down
6 changes: 5 additions & 1 deletion drivers/ufs/host/ufs-exynos.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ struct exynos_ufs_drv_data {
struct exynos_ufs_uic_attr *uic_attr;
unsigned int quirks;
unsigned int opts;
u32 iocc_mask;
/* SoC's specific operations */
int (*drv_init)(struct exynos_ufs *ufs);
int (*pre_link)(struct exynos_ufs *ufs);
Expand All @@ -191,6 +192,7 @@ struct exynos_ufs_drv_data {
const struct ufs_pa_layer_attr *pwr);
int (*pre_hce_enable)(struct exynos_ufs *ufs);
int (*post_hce_enable)(struct exynos_ufs *ufs);
int (*suspend)(struct exynos_ufs *ufs);
};

struct ufs_phy_time_cfg {
Expand Down Expand Up @@ -230,7 +232,9 @@ struct exynos_ufs {
ktime_t entry_hibern8_t;
const struct exynos_ufs_drv_data *drv_data;
struct regmap *sysreg;
u32 shareability_reg_offset;
u32 iocc_offset;
u32 iocc_mask;
u32 iocc_val;

u32 opts;
#define EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL BIT(0)
Expand Down

0 comments on commit 8a65b75

Please sign in to comment.