Skip to content

Commit

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

Hi Martin, James & Alim,

This series adds support to the ufs-exynos driver for Tensor gs101
found in Pixel 6. It was send previously in [1] and [2] but included
the other clock, phy and DTS parts. This series has been split into
just the ufs-exynos part to hopefully make things easier.

With this series, plus the phy, clock and dts changes UFS is
functional upstream for Pixel 6. The SKhynix HN8T05BZGKX015 can be
enumerated, partitions mounted etc.

The series is split into some prepatory patches for ufs-exynos and a
final patch that adds the gs101 support.

Note the sysreg clock has been moved to ufs node as fine grained clock
control around the syscon sysreg register accesses doesn't result in
functional UFS.

regards,

Peter

Link: https://lore.kernel.org/r/20240426122004.2249178-1-peter.griffin@linaro.org
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Martin K. Petersen committed May 7, 2024
2 parents 998d09c + d11e0a3 commit 0d9a1ec
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 18 deletions.
38 changes: 35 additions & 3 deletions Documentation/devicetree/bindings/ufs/samsung,exynos-ufs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ maintainers:
description: |
Each Samsung UFS host controller instance should have its own node.
allOf:
- $ref: ufs-common.yaml

properties:
compatible:
enum:
- google,gs101-ufs
- samsung,exynos7-ufs
- samsung,exynosautov9-ufs
- samsung,exynosautov9-ufs-vh
Expand All @@ -38,14 +36,24 @@ properties:
- const: ufsp

clocks:
minItems: 2
items:
- description: ufs link core clock
- description: unipro main clock
- description: fmp clock
- description: ufs aclk clock
- description: ufs pclk clock
- description: sysreg clock

clock-names:
minItems: 2
items:
- const: core_clk
- const: sclk_unipro_main
- const: fmp
- const: aclk
- const: pclk
- const: sysreg

phys:
maxItems: 1
Expand All @@ -72,6 +80,30 @@ required:
- clocks
- clock-names

allOf:
- $ref: ufs-common.yaml
- if:
properties:
compatible:
contains:
const: google,gs101-ufs

then:
properties:
clocks:
minItems: 6

clock-names:
minItems: 6

else:
properties:
clocks:
maxItems: 2

clock-names:
maxItems: 2

unevaluatedProperties: false

examples:
Expand Down
196 changes: 183 additions & 13 deletions drivers/ufs/host/ufs-exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
#define HCI_ERR_EN_N_LAYER 0x80
#define HCI_ERR_EN_T_LAYER 0x84
#define HCI_ERR_EN_DME_LAYER 0x88
#define HCI_V2P1_CTRL 0x8C
#define IA_TICK_SEL BIT(16)
#define HCI_CLKSTOP_CTRL 0xB0
#define REFCLKOUT_STOP BIT(4)
#define MPHY_APBCLK_STOP BIT(3)
Expand All @@ -59,6 +61,7 @@
#define CLK_STOP_MASK (REFCLKOUT_STOP | REFCLK_STOP |\
UNIPRO_MCLK_STOP | MPHY_APBCLK_STOP|\
UNIPRO_PCLK_STOP)
/* HCI_MISC is also known as HCI_FORCE_HCS */
#define HCI_MISC 0xB4
#define REFCLK_CTRL_EN BIT(7)
#define UNIPRO_PCLK_CTRL_EN BIT(6)
Expand Down Expand Up @@ -136,6 +139,9 @@ enum {
/*
* UNIPRO registers
*/
#define UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER0 0x7888
#define UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER1 0x788c
#define UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER2 0x7890
#define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER0 0x78B8
#define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER1 0x78BC
#define UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER2 0x78C0
Expand Down Expand Up @@ -306,8 +312,9 @@ static int exynosauto_ufs_post_pwr_change(struct exynos_ufs *ufs,

static int exynos7_ufs_pre_link(struct exynos_ufs *ufs)
{
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
u32 val = attr->pa_dbg_opt_suite1_val;
struct ufs_hba *hba = ufs->hba;
u32 val = ufs->drv_data->uic_attr->pa_dbg_option_suite;
int i;

exynos_ufs_enable_ov_tm(hba);
Expand All @@ -324,12 +331,13 @@ static int exynos7_ufs_pre_link(struct exynos_ufs *ufs)
UIC_ARG_MIB_SEL(TX_HIBERN8_CONTROL, i), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_TXPHY_CFGUPDT), 0x1);
udelay(1);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OPTION_SUITE), val | (1 << 12));
ufshcd_dme_set(hba, UIC_ARG_MIB(attr->pa_dbg_opt_suite1_off),
val | (1 << 12));
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_SKIP_RESET_PHY), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_SKIP_LINE_RESET), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_LINE_RESET_REQ), 0x1);
udelay(1600);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OPTION_SUITE), val);
ufshcd_dme_set(hba, UIC_ARG_MIB(attr->pa_dbg_opt_suite1_off), val);

return 0;
}
Expand Down Expand Up @@ -921,14 +929,23 @@ static int exynos_ufs_phy_init(struct exynos_ufs *ufs)

static void exynos_ufs_config_unipro(struct exynos_ufs *ufs)
{
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
struct ufs_hba *hba = ufs->hba;

ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_CLK_PERIOD),
DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
if (attr->pa_dbg_clk_period_off)
ufshcd_dme_set(hba, UIC_ARG_MIB(attr->pa_dbg_clk_period_off),
DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));

ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTRAILINGCLOCKS),
ufs->drv_data->uic_attr->tx_trailingclks);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OPTION_SUITE),
ufs->drv_data->uic_attr->pa_dbg_option_suite);

if (attr->pa_dbg_opt_suite1_off)
ufshcd_dme_set(hba, UIC_ARG_MIB(attr->pa_dbg_opt_suite1_off),
attr->pa_dbg_opt_suite1_val);

if (attr->pa_dbg_opt_suite2_off)
ufshcd_dme_set(hba, UIC_ARG_MIB(attr->pa_dbg_opt_suite2_off),
attr->pa_dbg_opt_suite2_val);
}

static void exynos_ufs_config_intr(struct exynos_ufs *ufs, u32 errs, u8 index)
Expand Down Expand Up @@ -1005,6 +1022,13 @@ static void exynos_ufs_fit_aggr_timeout(struct exynos_ufs *ufs)
{
u32 val;

/* Select function clock (mclk) for timer tick */
if (ufs->opts & EXYNOS_UFS_OPT_TIMER_TICK_SELECT) {
val = hci_readl(ufs, HCI_V2P1_CTRL);
val |= IA_TICK_SEL;
hci_writel(ufs, val, HCI_V2P1_CTRL);
}

val = exynos_ufs_calc_time_cntr(ufs, IATOVAL_NSEC / CNTR_DIV_VAL);
hci_writel(ufs, val & CNT_VAL_1US_MASK, HCI_1US_TO_CNT_VAL);
}
Expand Down Expand Up @@ -1186,7 +1210,8 @@ static int exynos_ufs_init(struct ufs_hba *hba)
if (ret)
goto out;
exynos_ufs_specify_phy_time_attr(ufs);
exynos_ufs_config_smu(ufs);
if (!(ufs->opts & EXYNOS_UFS_OPT_UFSPR_SECURE))
exynos_ufs_config_smu(ufs);

hba->host->dma_alignment = SZ_4K - 1;
return 0;
Expand Down Expand Up @@ -1477,10 +1502,11 @@ static int exynosauto_ufs_vh_init(struct ufs_hba *hba)

static int fsd_ufs_pre_link(struct exynos_ufs *ufs)
{
int i;
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
struct ufs_hba *hba = ufs->hba;
int i;

ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_CLK_PERIOD),
ufshcd_dme_set(hba, UIC_ARG_MIB(attr->pa_dbg_clk_period_off),
DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
ufshcd_dme_set(hba, UIC_ARG_MIB(0x201), 0x12);
ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40);
Expand All @@ -1504,7 +1530,9 @@ static int fsd_ufs_pre_link(struct exynos_ufs *ufs)

ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_AUTOMODE_THLD), 0x4E20);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OPTION_SUITE), 0x2e820183);

ufshcd_dme_set(hba, UIC_ARG_MIB(attr->pa_dbg_opt_suite1_off),
0x2e820183);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0x0);

exynos_ufs_establish_connt(ufs);
Expand Down Expand Up @@ -1568,6 +1596,96 @@ static int fsd_ufs_pre_pwr_change(struct exynos_ufs *ufs,
return 0;
}

static inline u32 get_mclk_period_unipro_18(struct exynos_ufs *ufs)
{
return (16 * 1000 * 1000000UL / ufs->mclk_rate);
}

static int gs101_ufs_pre_link(struct exynos_ufs *ufs)
{
struct ufs_hba *hba = ufs->hba;
int i;
u32 tx_line_reset_period, rx_line_reset_period;

rx_line_reset_period = (RX_LINE_RESET_TIME * ufs->mclk_rate)
/ NSEC_PER_MSEC;
tx_line_reset_period = (TX_LINE_RESET_TIME * ufs->mclk_rate)
/ NSEC_PER_MSEC;

unipro_writel(ufs, get_mclk_period_unipro_18(ufs), COMP_CLK_PERIOD);

ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40);

for_each_ufs_rx_lane(ufs, i) {
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, i),
DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, i), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE2, i),
(rx_line_reset_period >> 16) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE1, i),
(rx_line_reset_period >> 8) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE0, i),
(rx_line_reset_period) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x2f, i), 0x69);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x84, i), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x25, i), 0xf6);
}

for_each_ufs_tx_lane(ufs, i) {
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, i),
DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, i),
0x02);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, i),
(tx_line_reset_period >> 16) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, i),
(tx_line_reset_period >> 8) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE0, i),
(tx_line_reset_period) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x04, i), 1);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x7F, i), 0);
}

ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB(N_DEVICEID), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB(N_DEVICEID_VALID), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERDEVICEID), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB(T_CONNECTIONSTATE), CPORT_CONNECTED);
ufshcd_dme_set(hba, UIC_ARG_MIB(0xA006), 0x8000);

return 0;
}

static int gs101_ufs_post_link(struct exynos_ufs *ufs)
{
struct ufs_hba *hba = ufs->hba;

exynos_ufs_enable_dbg_mode(hba);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SAVECONFIGTIME), 0x3e8);
exynos_ufs_disable_dbg_mode(hba);

return 0;
}

static int gs101_ufs_pre_pwr_change(struct exynos_ufs *ufs,
struct ufs_pa_layer_attr *pwr)
{
struct ufs_hba *hba = ufs->hba;

ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), 12000);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), 32000);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), 16000);
unipro_writel(ufs, 8064, UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER0);
unipro_writel(ufs, 28224, UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER1);
unipro_writel(ufs, 20160, UNIPRO_DME_POWERMODE_REQ_LOCALL2TIMER2);
unipro_writel(ufs, 12000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER0);
unipro_writel(ufs, 32000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER1);
unipro_writel(ufs, 16000, UNIPRO_DME_POWERMODE_REQ_REMOTEL2TIMER2);

return 0;
}

static const struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
.name = "exynos_ufs",
.init = exynos_ufs_init,
Expand Down Expand Up @@ -1640,7 +1758,9 @@ static struct exynos_ufs_uic_attr exynos7_uic_attr = {
.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_option_suite = 0x30103,
.pa_dbg_clk_period_off = PA_DBG_CLK_PERIOD,
.pa_dbg_opt_suite1_val = 0x30103,
.pa_dbg_opt_suite1_off = PA_DBG_OPTION_SUITE,
};

static const struct exynos_ufs_drv_data exynosauto_ufs_drvs = {
Expand Down Expand Up @@ -1692,6 +1812,34 @@ static const struct exynos_ufs_drv_data exynos_ufs_drvs = {
.post_pwr_change = exynos7_ufs_post_pwr_change,
};

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,
.pa_dbg_opt_suite2_off = PA_GS101_DBG_OPTION_SUITE2,
};

static struct exynos_ufs_uic_attr fsd_uic_attr = {
.tx_trailingclks = 0x10,
.tx_dif_p_nsec = 3000000, /* unit: ns */
Expand All @@ -1714,7 +1862,9 @@ static struct exynos_ufs_uic_attr fsd_uic_attr = {
.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_option_suite = 0x2E820183,
.pa_dbg_clk_period_off = PA_DBG_CLK_PERIOD,
.pa_dbg_opt_suite1_val = 0x2E820183,
.pa_dbg_opt_suite1_off = PA_DBG_OPTION_SUITE,
};

static const struct exynos_ufs_drv_data fsd_ufs_drvs = {
Expand All @@ -1733,7 +1883,27 @@ static const struct exynos_ufs_drv_data fsd_ufs_drvs = {
.pre_pwr_change = fsd_ufs_pre_pwr_change,
};

static const struct exynos_ufs_drv_data gs101_ufs_drvs = {
.uic_attr = &gs101_uic_attr,
.quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR |
UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR |
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 |
EXYNOS_UFS_OPT_UFSPR_SECURE |
EXYNOS_UFS_OPT_TIMER_TICK_SELECT,
.drv_init = exynosauto_ufs_drv_init,
.pre_link = gs101_ufs_pre_link,
.post_link = gs101_ufs_post_link,
.pre_pwr_change = gs101_ufs_pre_pwr_change,
};

static const struct of_device_id exynos_ufs_of_match[] = {
{ .compatible = "google,gs101-ufs",
.data = &gs101_ufs_drvs },
{ .compatible = "samsung,exynos7-ufs",
.data = &exynos_ufs_drvs },
{ .compatible = "samsung,exynosautov9-ufs",
Expand Down
Loading

0 comments on commit 0d9a1ec

Please sign in to comment.