Commit 0d9a1ec6 authored by Martin K. Petersen's avatar Martin K. Petersen

Merge patch series "ufs-exynos support for Tensor GS101"

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.orgSigned-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parents 998d09c5 d11e0a31
......@@ -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
......@@ -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
......@@ -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:
......
......@@ -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)
......@@ -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)
......@@ -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
......@@ -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);
......@@ -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;
}
......@@ -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),
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)
......@@ -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);
}
......@@ -1186,6 +1210,7 @@ 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);
hba->host->dma_alignment = SZ_4K - 1;
......@@ -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);
......@@ -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);
......@@ -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,
......@@ -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 = {
......@@ -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 */
......@@ -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 = {
......@@ -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",
......
......@@ -9,6 +9,12 @@
#ifndef _UFS_EXYNOS_H_
#define _UFS_EXYNOS_H_
/*
* Component registers
*/
#define COMP_CLK_PERIOD 0x44
/*
* UNIPRO registers
*/
......@@ -29,6 +35,14 @@
#define PA_DBG_OPTION_SUITE 0x9564
#define PA_DBG_OPTION_SUITE_DYN 0x9565
/*
* Note: GS101_DBG_OPTION offsets below differ from the TRM
* but match the downstream driver. Following the TRM
* results in non-functioning UFS.
*/
#define PA_GS101_DBG_OPTION_SUITE1 0x956a
#define PA_GS101_DBG_OPTION_SUITE2 0x956d
/*
* MIBs for Transport Layer debug registers
*/
......@@ -116,7 +130,7 @@ struct exynos_ufs;
#define PA_HIBERN8TIME_VAL 0x20
#define PCLK_AVAIL_MIN 70000000
#define PCLK_AVAIL_MAX 167000000
#define PCLK_AVAIL_MAX 267000000
struct exynos_ufs_uic_attr {
/* TX Attributes */
......@@ -145,7 +159,11 @@ struct exynos_ufs_uic_attr {
/* Common Attributes */
unsigned int cmn_pwm_clk_ctrl;
/* Internal Attributes */
unsigned int pa_dbg_option_suite;
unsigned int pa_dbg_clk_period_off;
unsigned int pa_dbg_opt_suite1_val;
unsigned int pa_dbg_opt_suite1_off;
unsigned int pa_dbg_opt_suite2_val;
unsigned int pa_dbg_opt_suite2_off;
/* Changeable Attributes */
unsigned int rx_adv_fine_gran_sup_en;
unsigned int rx_adv_fine_gran_step;
......@@ -221,6 +239,8 @@ struct exynos_ufs {
#define EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX BIT(3)
#define EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER BIT(4)
#define EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR BIT(5)
#define EXYNOS_UFS_OPT_UFSPR_SECURE BIT(6)
#define EXYNOS_UFS_OPT_TIMER_TICK_SELECT BIT(7)
};
#define for_each_ufs_rx_lane(ufs, i) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment