Skip to content

Commit 8a65b75

Browse files
Merge patch series "ufs-exynos stability fixes for gs101"
Peter Griffin <[email protected]> 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/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
2 parents 72eea84 + cd4c002 commit 8a65b75

File tree

2 files changed

+68
-23
lines changed

2 files changed

+68
-23
lines changed

drivers/ufs/host/ufs-exynos.c

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* Exynos's Vendor specific registers for UFSHCI
3535
*/
3636
#define HCI_TXPRDT_ENTRY_SIZE 0x00
37-
#define PRDT_PREFECT_EN BIT(31)
37+
#define PRDT_PREFETCH_EN BIT(31)
3838
#define HCI_RXPRDT_ENTRY_SIZE 0x04
3939
#define HCI_1US_TO_CNT_VAL 0x0C
4040
#define CNT_VAL_1US_MASK 0x3FF
@@ -92,11 +92,16 @@
9292
UIC_TRANSPORT_NO_CONNECTION_RX |\
9393
UIC_TRANSPORT_BAD_TC)
9494

95-
/* FSYS UFS Shareability */
96-
#define UFS_WR_SHARABLE BIT(2)
97-
#define UFS_RD_SHARABLE BIT(1)
98-
#define UFS_SHARABLE (UFS_WR_SHARABLE | UFS_RD_SHARABLE)
99-
#define UFS_SHAREABILITY_OFFSET 0x710
95+
/* UFS Shareability */
96+
#define UFS_EXYNOSAUTO_WR_SHARABLE BIT(2)
97+
#define UFS_EXYNOSAUTO_RD_SHARABLE BIT(1)
98+
#define UFS_EXYNOSAUTO_SHARABLE (UFS_EXYNOSAUTO_WR_SHARABLE | \
99+
UFS_EXYNOSAUTO_RD_SHARABLE)
100+
#define UFS_GS101_WR_SHARABLE BIT(1)
101+
#define UFS_GS101_RD_SHARABLE BIT(0)
102+
#define UFS_GS101_SHARABLE (UFS_GS101_WR_SHARABLE | \
103+
UFS_GS101_RD_SHARABLE)
104+
#define UFS_SHAREABILITY_OFFSET 0x710
100105

101106
/* Multi-host registers */
102107
#define MHCTRL 0xC4
@@ -209,8 +214,8 @@ static int exynos_ufs_shareability(struct exynos_ufs *ufs)
209214
/* IO Coherency setting */
210215
if (ufs->sysreg) {
211216
return regmap_update_bits(ufs->sysreg,
212-
ufs->shareability_reg_offset,
213-
UFS_SHARABLE, UFS_SHARABLE);
217+
ufs->iocc_offset,
218+
ufs->iocc_mask, ufs->iocc_val);
214219
}
215220

216221
return 0;
@@ -957,6 +962,12 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs)
957962
}
958963

959964
phy_set_bus_width(generic_phy, ufs->avail_ln_rx);
965+
966+
if (generic_phy->power_count) {
967+
phy_power_off(generic_phy);
968+
phy_exit(generic_phy);
969+
}
970+
960971
ret = phy_init(generic_phy);
961972
if (ret) {
962973
dev_err(hba->dev, "%s: phy init failed, ret = %d\n",
@@ -1049,21 +1060,21 @@ static int exynos_ufs_pre_link(struct ufs_hba *hba)
10491060
exynos_ufs_config_intr(ufs, DFES_DEF_L4_ERRS, UNIPRO_L4);
10501061
exynos_ufs_set_unipro_pclk_div(ufs);
10511062

1063+
exynos_ufs_setup_clocks(hba, true, PRE_CHANGE);
1064+
10521065
/* unipro */
10531066
exynos_ufs_config_unipro(ufs);
10541067

1068+
if (ufs->drv_data->pre_link)
1069+
ufs->drv_data->pre_link(ufs);
1070+
10551071
/* m-phy */
10561072
exynos_ufs_phy_init(ufs);
10571073
if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR)) {
10581074
exynos_ufs_config_phy_time_attr(ufs);
10591075
exynos_ufs_config_phy_cap_attr(ufs);
10601076
}
10611077

1062-
exynos_ufs_setup_clocks(hba, true, PRE_CHANGE);
1063-
1064-
if (ufs->drv_data->pre_link)
1065-
ufs->drv_data->pre_link(ufs);
1066-
10671078
return 0;
10681079
}
10691080

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

10911103
exynos_ufs_establish_connt(ufs);
10921104
exynos_ufs_fit_aggr_timeout(ufs);
10931105

10941106
hci_writel(ufs, 0xa, HCI_DATA_REORDER);
1095-
hci_writel(ufs, ilog2(DATA_UNIT_SIZE), HCI_TXPRDT_ENTRY_SIZE);
1107+
1108+
if (hba->caps & UFSHCD_CAP_CRYPTO)
1109+
val |= PRDT_PREFETCH_EN;
1110+
hci_writel(ufs, val, HCI_TXPRDT_ENTRY_SIZE);
1111+
10961112
hci_writel(ufs, ilog2(DATA_UNIT_SIZE), HCI_RXPRDT_ENTRY_SIZE);
10971113
hci_writel(ufs, (1 << hba->nutrs) - 1, HCI_UTRL_NEXUS_TYPE);
10981114
hci_writel(ufs, (1 << hba->nutmrs) - 1, HCI_UTMRL_NEXUS_TYPE);
@@ -1168,12 +1184,22 @@ static int exynos_ufs_parse_dt(struct device *dev, struct exynos_ufs *ufs)
11681184
ufs->sysreg = NULL;
11691185
else {
11701186
if (of_property_read_u32_index(np, "samsung,sysreg", 1,
1171-
&ufs->shareability_reg_offset)) {
1187+
&ufs->iocc_offset)) {
11721188
dev_warn(dev, "can't get an offset from sysreg. Set to default value\n");
1173-
ufs->shareability_reg_offset = UFS_SHAREABILITY_OFFSET;
1189+
ufs->iocc_offset = UFS_SHAREABILITY_OFFSET;
11741190
}
11751191
}
11761192

1193+
ufs->iocc_mask = ufs->drv_data->iocc_mask;
1194+
/*
1195+
* no 'dma-coherent' property means the descriptors are
1196+
* non-cacheable so iocc shareability should be disabled.
1197+
*/
1198+
if (of_dma_is_coherent(dev->of_node))
1199+
ufs->iocc_val = ufs->iocc_mask;
1200+
else
1201+
ufs->iocc_val = 0;
1202+
11771203
ufs->pclk_avail_min = PCLK_AVAIL_MIN;
11781204
ufs->pclk_avail_max = PCLK_AVAIL_MAX;
11791205

@@ -1496,6 +1522,14 @@ static int exynos_ufs_init(struct ufs_hba *hba)
14961522
return ret;
14971523
}
14981524

1525+
static void exynos_ufs_exit(struct ufs_hba *hba)
1526+
{
1527+
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
1528+
1529+
phy_power_off(ufs->phy);
1530+
phy_exit(ufs->phy);
1531+
}
1532+
14991533
static int exynos_ufs_host_reset(struct ufs_hba *hba)
15001534
{
15011535
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
@@ -1666,6 +1700,12 @@ static void exynos_ufs_hibern8_notify(struct ufs_hba *hba,
16661700
}
16671701
}
16681702

1703+
static int gs101_ufs_suspend(struct exynos_ufs *ufs)
1704+
{
1705+
hci_writel(ufs, 0 << 0, HCI_GPIO_OUT);
1706+
return 0;
1707+
}
1708+
16691709
static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
16701710
enum ufs_notify_change_status status)
16711711
{
@@ -1674,6 +1714,9 @@ static int exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
16741714
if (status == PRE_CHANGE)
16751715
return 0;
16761716

1717+
if (ufs->drv_data->suspend)
1718+
ufs->drv_data->suspend(ufs);
1719+
16771720
if (!ufshcd_is_link_active(hba))
16781721
phy_power_off(ufs->phy);
16791722

@@ -1951,6 +1994,7 @@ static int gs101_ufs_pre_pwr_change(struct exynos_ufs *ufs,
19511994
static const struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
19521995
.name = "exynos_ufs",
19531996
.init = exynos_ufs_init,
1997+
.exit = exynos_ufs_exit,
19541998
.hce_enable_notify = exynos_ufs_hce_enable_notify,
19551999
.link_startup_notify = exynos_ufs_link_startup_notify,
19562000
.pwr_change_notify = exynos_ufs_pwr_change_notify,
@@ -1989,13 +2033,7 @@ static int exynos_ufs_probe(struct platform_device *pdev)
19892033

19902034
static void exynos_ufs_remove(struct platform_device *pdev)
19912035
{
1992-
struct ufs_hba *hba = platform_get_drvdata(pdev);
1993-
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
1994-
19952036
ufshcd_pltfrm_remove(pdev);
1996-
1997-
phy_power_off(ufs->phy);
1998-
phy_exit(ufs->phy);
19992037
}
20002038

20012039
static struct exynos_ufs_uic_attr exynos7_uic_attr = {
@@ -2034,6 +2072,7 @@ static const struct exynos_ufs_drv_data exynosauto_ufs_drvs = {
20342072
.opts = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
20352073
EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
20362074
EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX,
2075+
.iocc_mask = UFS_EXYNOSAUTO_SHARABLE,
20372076
.drv_init = exynosauto_ufs_drv_init,
20382077
.post_hce_enable = exynosauto_ufs_post_hce_enable,
20392078
.pre_link = exynosauto_ufs_pre_link,
@@ -2135,10 +2174,12 @@ static const struct exynos_ufs_drv_data gs101_ufs_drvs = {
21352174
.opts = EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
21362175
EXYNOS_UFS_OPT_UFSPR_SECURE |
21372176
EXYNOS_UFS_OPT_TIMER_TICK_SELECT,
2177+
.iocc_mask = UFS_GS101_SHARABLE,
21382178
.drv_init = gs101_ufs_drv_init,
21392179
.pre_link = gs101_ufs_pre_link,
21402180
.post_link = gs101_ufs_post_link,
21412181
.pre_pwr_change = gs101_ufs_pre_pwr_change,
2182+
.suspend = gs101_ufs_suspend,
21422183
};
21432184

21442185
static const struct of_device_id exynos_ufs_of_match[] = {

drivers/ufs/host/ufs-exynos.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ struct exynos_ufs_drv_data {
181181
struct exynos_ufs_uic_attr *uic_attr;
182182
unsigned int quirks;
183183
unsigned int opts;
184+
u32 iocc_mask;
184185
/* SoC's specific operations */
185186
int (*drv_init)(struct exynos_ufs *ufs);
186187
int (*pre_link)(struct exynos_ufs *ufs);
@@ -191,6 +192,7 @@ struct exynos_ufs_drv_data {
191192
const struct ufs_pa_layer_attr *pwr);
192193
int (*pre_hce_enable)(struct exynos_ufs *ufs);
193194
int (*post_hce_enable)(struct exynos_ufs *ufs);
195+
int (*suspend)(struct exynos_ufs *ufs);
194196
};
195197

196198
struct ufs_phy_time_cfg {
@@ -230,7 +232,9 @@ struct exynos_ufs {
230232
ktime_t entry_hibern8_t;
231233
const struct exynos_ufs_drv_data *drv_data;
232234
struct regmap *sysreg;
233-
u32 shareability_reg_offset;
235+
u32 iocc_offset;
236+
u32 iocc_mask;
237+
u32 iocc_val;
234238

235239
u32 opts;
236240
#define EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL BIT(0)

0 commit comments

Comments
 (0)