[PATCH] ufs: amd-versal2: Configure RMMI and M-PHY registers for HS mode

neil.armstrong at linaro.org neil.armstrong at linaro.org
Thu Jul 24 10:22:23 CEST 2025


On 24/07/2025 06:44, Venkatesh Yadav Abbarapu wrote:
> Configure RMMI and M-PHY registers for HS mode required for selection of
> bit rate series A or B. If it is not a calibrated part, then switch back
> to SLOWAUTO_MODE and skip all these configurations.
> Implemented below sequence as per the DWC RMMI databook.
> 1. Override RMMI CBRATESEL with the desired rate.
> 2. Set TX_CFGUPDT_0 to 1'b1 for one TX_CFGCLK_0 cycle.
> 3. Override PHY rx_req to 1, then poll on PHY rx_ack register till it
> goes 1(both lanes).
> 4. Override PHY rx_req to 0, then poll on PHY rx_ack register till it
> goes 0(both lanes).
> 5. Remove PHY rx_req override(both lanes).
> 6. Start the LS PMC.
> 
> Signed-off-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu at amd.com>
> ---
>   drivers/ufs/ufs-amd-versal2.c | 112 ++++++++++++++++++++++++++++++++++
>   drivers/ufs/ufs.c             |  15 +++++
>   drivers/ufs/ufs.h             |   3 +
>   drivers/ufs/ufshcd-dwc.h      |   3 +
>   4 files changed, 133 insertions(+)
> 
> diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c
> index 1c5ed538370..896dda2de4e 100644
> --- a/drivers/ufs/ufs-amd-versal2.c
> +++ b/drivers/ufs/ufs-amd-versal2.c
> @@ -26,6 +26,10 @@
>   #define MPHY_FAST_RX_AFE_CAL		BIT(2)
>   #define MPHY_FW_CALIB_CFG_VAL		BIT(8)
>   
> +#define MPHY_RX_OVRD_EN			BIT(3)
> +#define MPHY_RX_OVRD_VAL		BIT(2)
> +#define MPHY_RX_ACK_MASK		BIT(0)
> +
>   #define TX_RX_CFG_RDY_MASK		GENMASK(3, 0)
>   
>   #define TIMEOUT_MICROSEC		1000000L
> @@ -422,10 +426,118 @@ static int ufs_versal2_link_startup_notify(struct ufs_hba *hba,
>   	return ret;
>   }
>   
> +static int ufs_versal2_phy_ratesel(struct ufs_hba *hba, u32 activelanes, u32 rx_req)
> +{
> +	u32 time_left, reg, lane;
> +	int ret;
> +
> +	for (lane = 0; lane < activelanes; lane++) {
> +		time_left = TIMEOUT_MICROSEC;
> +		ret = ufs_versal2_phy_reg_read(hba, RX_OVRD_IN_1(lane), &reg);
> +		if (ret)
> +			return ret;
> +
> +		reg |= MPHY_RX_OVRD_EN;
> +		if (rx_req)
> +			reg |= MPHY_RX_OVRD_VAL;
> +		else
> +			reg &= ~MPHY_RX_OVRD_VAL;
> +
> +		ret = ufs_versal2_phy_reg_write(hba, RX_OVRD_IN_1(lane), reg);
> +		if (ret)
> +			return ret;
> +
> +		do {
> +			ret = ufs_versal2_phy_reg_read(hba, RX_PCS_OUT(lane), &reg);
> +			if (ret)
> +				return ret;
> +
> +			reg &= MPHY_RX_ACK_MASK;
> +			if (reg == rx_req)
> +				break;
> +
> +			time_left--;
> +			mdelay(5);
> +		} while (time_left);
> +
> +		if (!time_left) {
> +			dev_err(hba->dev, "Invalid Rx Ack value.\n");
> +			return -ETIMEDOUT;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int ufs_get_max_pwr_mode(struct ufs_hba *hba,
> +				struct ufs_pwr_mode_info *max_pwr_info)
> +{
> +	struct ufs_versal2_priv *priv = dev_get_priv(hba->dev);
> +	u32 lane, reg, rate = 0;
> +	int ret = 0;
> +
> +	/* If it is not a calibrated part, switch PWRMODE to SLOW_MODE */
> +	if (!priv->attcompval0 && !priv->attcompval1 &&
> +	    !priv->ctlecompval0 && !priv->ctlecompval1) {
> +		max_pwr_info->info.pwr_rx = SLOWAUTO_MODE;
> +		max_pwr_info->info.pwr_tx = SLOWAUTO_MODE;
> +		max_pwr_info->info.gear_rx = UFS_PWM_G1;
> +		max_pwr_info->info.gear_tx = UFS_PWM_G1;
> +		max_pwr_info->info.lane_tx = 1;
> +		max_pwr_info->info.lane_rx = 1;
> +		max_pwr_info->info.hs_rate = 0;
> +			return 0;
> +	}
> +
> +	if (max_pwr_info->info.pwr_rx == SLOWAUTO_MODE ||
> +	    max_pwr_info->info.pwr_tx == SLOWAUTO_MODE)
> +		return 0;
> +
> +	if (max_pwr_info->info.hs_rate == PA_HS_MODE_B)
> +		rate = 1;
> +
> +	/* Select the rate */
> +	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(CBRATESEL), rate);
> +	if (ret)
> +		return ret;
> +
> +	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = ufs_versal2_phy_ratesel(hba, max_pwr_info->info.lane_tx, 1);
> +	if (ret)
> +		return ret;
> +
> +	ret = ufs_versal2_phy_ratesel(hba, max_pwr_info->info.lane_tx, 0);
> +	if (ret)
> +		return ret;
> +
> +	/* Remove rx_req override */
> +	for (lane = 0; lane < max_pwr_info->info.lane_tx; lane++) {
> +		ret = ufs_versal2_phy_reg_read(hba, RX_OVRD_IN_1(lane), &reg);
> +		if (ret)
> +			return ret;
> +
> +		reg &= ~MPHY_RX_OVRD_EN;
> +		ret = ufs_versal2_phy_reg_write(hba, RX_OVRD_IN_1(lane), reg);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (max_pwr_info->info.lane_tx == UFS_LANE_2 &&
> +	    max_pwr_info->info.lane_rx == UFS_LANE_2)
> +		ret = ufshcd_dme_configure_adapt(hba, max_pwr_info->info.gear_tx,
> +						 PA_INITIAL_ADAPT);
> +
> +	return 0;
> +}
> +
>   static struct ufs_hba_ops ufs_versal2_hba_ops = {
>   	.init = ufs_versal2_init,
>   	.link_startup_notify = ufs_versal2_link_startup_notify,
>   	.hce_enable_notify = ufs_versal2_hce_enable_notify,
> +	.get_max_pwr_mode = ufs_get_max_pwr_mode,
>   };
>   
>   static int ufs_versal2_probe(struct udevice *dev)
> diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
> index 91f6ad3bfef..57e6e8c013b 100644
> --- a/drivers/ufs/ufs.c
> +++ b/drivers/ufs/ufs.c
> @@ -226,6 +226,21 @@ static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
>   	return 0;
>   }
>   
> +int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
> +			       int agreed_gear,
> +			       int adapt_val)
> +{
> +	int ret;
> +
> +	if (agreed_gear < UFS_HS_G4)
> +		adapt_val = PA_NO_ADAPT;
> +
> +	ret = ufshcd_dme_set(hba,
> +			     UIC_ARG_MIB(PA_TXHSADAPTTYPE),
> +			     adapt_val);
> +	return ret;
> +}
> +
>   /**
>    * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
>    *
> diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
> index 53137fae3a8..0337ac5996b 100644
> --- a/drivers/ufs/ufs.h
> +++ b/drivers/ufs/ufs.h
> @@ -428,6 +428,9 @@ enum uic_link_state {
>   #define ATTR_SET_NOR	0	/* NORMAL */
>   #define ATTR_SET_ST	1	/* STATIC */
>   
> +int ufshcd_dme_configure_adapt(struct ufs_hba *hba,
> +			       int agreed_gear,
> +			       int adapt_val);
>   int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
>   			u8 attr_set, u32 mib_val, u8 peer);
>   int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
> diff --git a/drivers/ufs/ufshcd-dwc.h b/drivers/ufs/ufshcd-dwc.h
> index fc1bcca8ccb..f7d27736f44 100644
> --- a/drivers/ufs/ufshcd-dwc.h
> +++ b/drivers/ufs/ufshcd-dwc.h
> @@ -17,6 +17,7 @@
>   #define CBREFCLKCTRL2		0x8132
>   #define CBCRCTRL		0x811F
>   #define CBC10DIRECTCONF2	0x810E
> +#define CBRATESEL		0x8114
>   #define CBCREGADDRLSB		0x8116
>   #define CBCREGADDRMSB		0x8117
>   #define CBCREGWRLSB		0x8118
> @@ -32,6 +33,8 @@
>   #define MRX_FSM_STATE		0xC1
>   
>   /* M-PHY registers */
> +#define RX_OVRD_IN_1(n)		(0x3006 + ((n) * 0x100))
> +#define RX_PCS_OUT(n)		(0x300F + ((n) * 0x100))
>   #define FAST_FLAGS(n)		(0x401C + ((n) * 0x100))
>   #define RX_AFE_ATT_IDAC(n)	(0x4000 + ((n) * 0x100))
>   #define RX_AFE_CTLE_IDAC(n)	(0x4001 + ((n) * 0x100))

Looks good !

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>


More information about the U-Boot mailing list