[PATCH v2 1/1] arm64: zynqmp: Enable usb3 for k24 som

Michal Simek michal.simek at amd.com
Mon Dec 18 15:00:37 CET 2023



On 12/15/23 08:40, Neal Frager wrote:
> Currently, the u-boot zynqmp psgtr driver is not connected to the usb dwc3
> driver.  Without this, the only way for u-boot to be able to use usb3 is if
> the psgtr serdes clocking is already enabled in the psu_init_gpl.c.  This
> patch enables the psgtr serdes for usb3 use, so the u-boot dwc3 driver will
> work properly on boards based on the k24 som.
> 
> In addition, this patch correctly configures mio76 and mio77 as gpio pins
> which are used as reset gpio pins on the kd240 starter kit.
> 
> This patch is needed for enabling u-boot to load an OS on the kd240
> starter kit by either usb3 or the sd card interface connected over the usb3
> to sd card bridge.
> 
> Signed-off-by: Neal Frager <neal.frager at amd.com>
> ---
> V1->V2:
>   - rebased patch to latest u-boot master branch
>   - improved git commit message
> ---
>   .../zynqmp/zynqmp-sm-k24-revA/psu_init_gpl.c  | 283 +++++++++++++++++-
>   1 file changed, 270 insertions(+), 13 deletions(-)
> 
> diff --git a/board/xilinx/zynqmp/zynqmp-sm-k24-revA/psu_init_gpl.c b/board/xilinx/zynqmp/zynqmp-sm-k24-revA/psu_init_gpl.c
> index 166e61431b..591f093752 100644
> --- a/board/xilinx/zynqmp/zynqmp-sm-k24-revA/psu_init_gpl.c
> +++ b/board/xilinx/zynqmp/zynqmp-sm-k24-revA/psu_init_gpl.c
> @@ -72,6 +72,18 @@ static void dpll_prog(int div2, int ddr_pll_fbdiv, int d_lock_dly,
>   	Xil_Out32(((0xFD1A0000U) + 0x0000002C), pll_ctrl_regval);
>   }
>   
> +static int serdes_illcalib(u32 lane3_protocol, u32 lane3_rate,
> +			   u32 lane2_protocol, u32 lane2_rate,
> +			   u32 lane1_protocol, u32 lane1_rate,
> +			   u32 lane0_protocol, u32 lane0_rate)
> +{
> +	Xil_Out32(0xFD409914, 0xF3);
> +	Xil_Out32(0xFD409940, 0xF3);
> +	Xil_Out32(0xFD409990, 0x20);
> +	Xil_Out32(0xFD409924, 0x37);
> +	return 1;
> +}

 From here

> +
>   static unsigned long psu_pll_init_data(void)
>   {
>   	psu_mask_write(0xFF5E0034, 0xFE7FEDEFU, 0x7E4B0C62U);
> @@ -528,8 +540,8 @@ static unsigned long psu_mio_init_data(void)
>   	psu_mask_write(0xFF180124, 0x000000FEU, 0x00000002U);
>   	psu_mask_write(0xFF180128, 0x000000FEU, 0x00000002U);
>   	psu_mask_write(0xFF18012C, 0x000000FEU, 0x00000002U);
> -	psu_mask_write(0xFF180130, 0x000000FEU, 0x000000C0U);
> -	psu_mask_write(0xFF180134, 0x000000FEU, 0x000000C0U);
> +	psu_mask_write(0xFF180130, 0x000000FEU, 0x00000000U);
> +	psu_mask_write(0xFF180134, 0x000000FEU, 0x00000000U);
>   	psu_mask_write(0xFF180204, 0xFFFFFFFFU, 0x50000000U);
>   	psu_mask_write(0xFF180208, 0xFFFFFFFFU, 0x00B02020U);
>   	psu_mask_write(0xFF18020C, 0x00003FFFU, 0x00000FC0U);
> @@ -569,21 +581,16 @@ static unsigned long psu_peripherals_init_data(void)
>   	psu_mask_write(0xFD1A0100, 0x0001807CU, 0x00000000U);
>   	psu_mask_write(0xFF5E0238, 0x001A0000U, 0x00000000U);
>   	psu_mask_write(0xFF5E023C, 0x0093C018U, 0x00000000U);
> -	psu_mask_write(0xFF5E0230, 0x00000008U, 0x00000000U);
> +	psu_mask_write(0xFF5E0230, 0x00000002U, 0x00000000U);
>   	psu_mask_write(0xFF5E0238, 0x00000001U, 0x00000000U);
>   	psu_mask_write(0xFF180390, 0x00000004U, 0x00000004U);
>   	psu_mask_write(0xFF5E023C, 0x00000400U, 0x00000000U);
> -	psu_mask_write(0xFF5E0238, 0x00000040U, 0x00000000U);
> -	psu_mask_write(0xFF180310, 0x00008000U, 0x00000000U);
> -	psu_mask_write(0xFF180320, 0x33840000U, 0x02840000U);
> -	psu_mask_write(0xFF18031C, 0x7FFE0000U, 0x64500000U);
> -	psu_mask_write(0xFF180358, 0x00000008U, 0x00000008U);
> -	psu_mask_write(0xFF180324, 0x03C00000U, 0x00000000U);
> +	psu_mask_write(0xFF5E0238, 0x00000080U, 0x00000000U);
>   	psu_mask_write(0xFF5E0238, 0x00000400U, 0x00000000U);
>   	psu_mask_write(0xFF5E0238, 0x00008000U, 0x00000000U);
>   	psu_mask_write(0xFF5E0238, 0x00000010U, 0x00000000U);
>   	psu_mask_write(0xFF5E0238, 0x00007800U, 0x00000000U);
> -	psu_mask_write(0xFF5E0238, 0x00000004U, 0x00000000U);
> +	psu_mask_write(0xFF5E0238, 0x00000006U, 0x00000000U);
>   	psu_mask_write(0xFF5E0238, 0x00040000U, 0x00000000U);
>   	psu_mask_write(0xFF4B0024, 0x000000FFU, 0x000000FFU);
>   	psu_mask_write(0xFFCA5000, 0x00001FFFU, 0x00000000U);
> @@ -591,13 +598,111 @@ static unsigned long psu_peripherals_init_data(void)
>   	psu_mask_write(0xFFA60040, 0x80000000U, 0x80000000U);
>   	psu_mask_write(0xFF260020, 0xFFFFFFFFU, 0x05F5DD18U);
>   	psu_mask_write(0xFF260000, 0x00000001U, 0x00000001U);
> -	psu_mask_write(0xFF5E0250, 0x00000F0FU, 0x00000202U);
> +	psu_mask_write(0xFF0A0284, 0x03FFFFFFU, 0x01000000U);
> +	psu_mask_write(0xFF0A0288, 0x03FFFFFFU, 0x01000000U);
> +	psu_mask_write(0xFF0A0014, 0x03FF03FFU, 0x02FF0100U);
>   
>   	mask_delay(1);
> -	psu_mask_write(0xFF5E0250, 0x00000F0FU, 0x00000002U);
> +	psu_mask_write(0xFF0A0014, 0x03FF03FFU, 0x02FF0000U);
>   
>   	mask_delay(5);
> -	psu_mask_write(0xFF5E0250, 0x00000F0FU, 0x00000202U);
> +	psu_mask_write(0xFF0A0014, 0x03FF03FFU, 0x02FF0100U);
> +
> +	return 1;
> +}

to here that's key part for getting things up and running.
And these are not serdes related configurations.

> +
> +static unsigned long psu_serdes_init_data(void)
> +{
> +	psu_mask_write(0xFD410008, 0x0000001FU, 0x00000008U);
> +	psu_mask_write(0xFD402868, 0x00000080U, 0x00000080U);
> +	psu_mask_write(0xFD40A094, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD40A368, 0x000000FFU, 0x00000038U);
> +	psu_mask_write(0xFD40A36C, 0x00000007U, 0x00000003U);
> +	psu_mask_write(0xFD40A370, 0x000000FFU, 0x000000F4U);
> +	psu_mask_write(0xFD40A374, 0x000000FFU, 0x00000031U);
> +	psu_mask_write(0xFD40A378, 0x000000FFU, 0x00000002U);
> +	psu_mask_write(0xFD40A37C, 0x00000033U, 0x00000030U);
> +	psu_mask_write(0xFD40906C, 0x00000003U, 0x00000003U);
> +	psu_mask_write(0xFD4080F4, 0x00000003U, 0x00000003U);
> +	psu_mask_write(0xFD4090CC, 0x00000020U, 0x00000020U);
> +	psu_mask_write(0xFD401074, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD405074, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD409074, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD40D074, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD401994, 0x00000007U, 0x00000007U);
> +	psu_mask_write(0xFD405994, 0x00000007U, 0x00000007U);
> +	psu_mask_write(0xFD40989C, 0x00000080U, 0x00000080U);
> +	psu_mask_write(0xFD4098F8, 0x000000FFU, 0x0000001AU);
> +	psu_mask_write(0xFD4098FC, 0x000000FFU, 0x0000001AU);
> +	psu_mask_write(0xFD409990, 0x000000FFU, 0x00000010U);
> +	psu_mask_write(0xFD409924, 0x000000FFU, 0x000000FEU);
> +	psu_mask_write(0xFD409928, 0x000000FFU, 0x00000000U);
> +	psu_mask_write(0xFD409900, 0x000000FFU, 0x0000001AU);
> +	psu_mask_write(0xFD40992C, 0x000000FFU, 0x00000000U);
> +	psu_mask_write(0xFD409980, 0x000000FFU, 0x000000FFU);
> +	psu_mask_write(0xFD409914, 0x000000FFU, 0x000000F7U);
> +	psu_mask_write(0xFD409918, 0x00000001U, 0x00000001U);
> +	psu_mask_write(0xFD409940, 0x000000FFU, 0x000000F7U);
> +	psu_mask_write(0xFD409944, 0x00000001U, 0x00000001U);
> +	psu_mask_write(0xFD409994, 0x00000007U, 0x00000007U);
> +	psu_mask_write(0xFD40D994, 0x00000007U, 0x00000007U);
> +	psu_mask_write(0xFD40107C, 0x0000000FU, 0x00000001U);
> +	psu_mask_write(0xFD40507C, 0x0000000FU, 0x00000001U);
> +	psu_mask_write(0xFD40907C, 0x0000000FU, 0x00000001U);
> +	psu_mask_write(0xFD40D07C, 0x0000000FU, 0x00000001U);
> +	psu_mask_write(0xFD4019A4, 0x000000FFU, 0x000000FFU);
> +	psu_mask_write(0xFD401038, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD40102C, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD4059A4, 0x000000FFU, 0x000000FFU);
> +	psu_mask_write(0xFD405038, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD40502C, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD4099A4, 0x000000FFU, 0x000000FFU);
> +	psu_mask_write(0xFD409038, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD40902C, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD40D9A4, 0x000000FFU, 0x000000FFU);
> +	psu_mask_write(0xFD40D038, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD40D02C, 0x00000040U, 0x00000040U);
> +	psu_mask_write(0xFD4019AC, 0x00000003U, 0x00000000U);
> +	psu_mask_write(0xFD4059AC, 0x00000003U, 0x00000000U);
> +	psu_mask_write(0xFD4099AC, 0x00000003U, 0x00000000U);
> +	psu_mask_write(0xFD40D9AC, 0x00000003U, 0x00000000U);
> +	psu_mask_write(0xFD401978, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD405978, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD409978, 0x00000010U, 0x00000010U);
> +	psu_mask_write(0xFD40D978, 0x00000010U, 0x00000010U);
> +
> +	serdes_illcalib(0, 0, 3, 0, 0, 0, 0, 0);
> +	psu_mask_write(0xFD410014, 0x00000007U, 0x00000003U);
> +	return 1;
> +}
> +
> +static unsigned long psu_resetout_init_data(void)
> +{
> +	psu_mask_write(0xFF5E023C, 0x00000400U, 0x00000000U);
> +	psu_mask_write(0xFF9D0080, 0x00000001U, 0x00000001U);
> +	psu_mask_write(0xFF9D007C, 0x00000001U, 0x00000000U);
> +	psu_mask_write(0xFF5E023C, 0x00000140U, 0x00000000U);
> +	psu_mask_write(0xFF5E0230, 0x00000002U, 0x00000000U);
> +	psu_mask_write(0xFD1A0100, 0x00010000U, 0x00000000U);
> +	psu_mask_write(0xFD4A0200, 0x00000002U, 0x00000000U);
> +	psu_mask_write(0xFD4A0238, 0x0000000FU, 0x00000000U);
> +	psu_mask_write(0xFE20C200, 0x00023FFFU, 0x00022457U);
> +	psu_mask_write(0xFE20C630, 0x003FFF00U, 0x00000000U);
> +	psu_mask_write(0xFE20C11C, 0x00000600U, 0x00000600U);
> +	psu_mask_write(0xFE20C12C, 0x00004000U, 0x00004000U);
> +	psu_mask_write(0xFD480064, 0x00000200U, 0x00000200U);
> +	mask_poll(0xFD40A3E4, 0x00000010U);
> +
> +	return 1;
> +}
> +
> +static unsigned long psu_resetin_init_data(void)
> +{
> +	psu_mask_write(0xFF5E023C, 0x00000540U, 0x00000540U);
> +	psu_mask_write(0xFF5E0230, 0x00000002U, 0x00000002U);
> +	psu_mask_write(0xFD4A0238, 0x0000000FU, 0x0000000AU);
> +	psu_mask_write(0xFD4A0200, 0x00000002U, 0x00000002U);
> +	psu_mask_write(0xFD1A0100, 0x00010000U, 0x00010000U);
>   
>   	return 1;
>   }
> @@ -911,6 +1016,157 @@ static unsigned long psu_ddr_phybringup_data(void)
>   	return 1;
>   }
>   
> +static int serdes_enb_coarse_saturation(void)
> +{
> +	Xil_Out32(0xFD402094, 0x00000010);
> +	Xil_Out32(0xFD406094, 0x00000010);
> +	Xil_Out32(0xFD40A094, 0x00000010);
> +	Xil_Out32(0xFD40E094, 0x00000010);
> +	return 1;
> +}
> +
> +static int serdes_fixcal_code(void)
> +{
> +	int maskstatus = 1;
> +	unsigned int rdata = 0;
> +	unsigned int match_pmos_code[23];
> +	unsigned int match_nmos_code[23];
> +	unsigned int match_ical_code[7];
> +	unsigned int match_rcal_code[7];
> +	unsigned int p_code = 0;
> +	unsigned int n_code = 0;
> +	unsigned int i_code = 0;
> +	unsigned int r_code = 0;
> +	unsigned int repeat_count = 0;
> +	unsigned int L3_TM_CALIB_DIG20 = 0;
> +	unsigned int L3_TM_CALIB_DIG19 = 0;
> +	unsigned int L3_TM_CALIB_DIG18 = 0;
> +	unsigned int L3_TM_CALIB_DIG16 = 0;
> +	unsigned int L3_TM_CALIB_DIG15 = 0;
> +	unsigned int L3_TM_CALIB_DIG14 = 0;
> +	int i = 0;
> +
> +	rdata = Xil_In32(0xFD40289C);
> +	rdata = rdata & ~0x03;
> +	rdata = rdata | 0x1;
> +	Xil_Out32(0xFD40289C, rdata);
> +	int count = 0;
> +	do {
> +		if (count == 1100000)
> +			break;
> +		rdata = Xil_In32(0xFD402B1C);
> +		count++;
> +	} while ((rdata & 0x0000000E) != 0x0000000E);
> +
> +	for (i = 0; i < 23; i++) {
> +		match_pmos_code[i] = 0;
> +		match_nmos_code[i] = 0;
> +	}
> +	for (i = 0; i < 7; i++) {
> +		match_ical_code[i] = 0;
> +		match_rcal_code[i] = 0;
> +	}
> +
> +	do {
> +		Xil_Out32(0xFD410010, 0x00000000);
> +		Xil_Out32(0xFD410014, 0x00000000);
> +
> +		Xil_Out32(0xFD410010, 0x00000001);
> +		Xil_Out32(0xFD410014, 0x00000000);
> +
> +		maskstatus = mask_poll(0xFD40EF14, 0x2);
> +		if (maskstatus == 0) {
> +			xil_printf("#SERDES initialization timed out\n\r");
> +			return maskstatus;
> +		}
> +
> +		p_code = mask_read(0xFD40EF18, 0xFFFFFFFF);
> +		n_code = mask_read(0xFD40EF1C, 0xFFFFFFFF);
> +		;
> +		i_code = mask_read(0xFD40EF24, 0xFFFFFFFF);
> +		r_code = mask_read(0xFD40EF28, 0xFFFFFFFF);
> +		;
> +
> +		if (p_code >= 0x26 && p_code <= 0x3C)
> +			match_pmos_code[p_code - 0x26] += 1;
> +
> +		if (n_code >= 0x26 && n_code <= 0x3C)
> +			match_nmos_code[n_code - 0x26] += 1;
> +
> +		if (i_code >= 0xC && i_code <= 0x12)
> +			match_ical_code[i_code - 0xC] += 1;
> +
> +		if (r_code >= 0x6 && r_code <= 0xC)
> +			match_rcal_code[r_code - 0x6] += 1;
> +
> +	} while (repeat_count++ < 10);
> +
> +	for (i = 0; i < 23; i++) {
> +		if (match_pmos_code[i] >= match_pmos_code[0]) {
> +			match_pmos_code[0] = match_pmos_code[i];
> +			p_code = 0x26 + i;
> +		}
> +		if (match_nmos_code[i] >= match_nmos_code[0]) {
> +			match_nmos_code[0] = match_nmos_code[i];
> +			n_code = 0x26 + i;
> +		}
> +	}
> +
> +	for (i = 0; i < 7; i++) {
> +		if (match_ical_code[i] >= match_ical_code[0]) {
> +			match_ical_code[0] = match_ical_code[i];
> +			i_code = 0xC + i;
> +		}
> +		if (match_rcal_code[i] >= match_rcal_code[0]) {
> +			match_rcal_code[0] = match_rcal_code[i];
> +			r_code = 0x6 + i;
> +		}
> +	}
> +
> +	L3_TM_CALIB_DIG20 = mask_read(0xFD40EC50, 0xFFFFFFF0);
> +	L3_TM_CALIB_DIG20 = L3_TM_CALIB_DIG20 | 0x8 | ((p_code >> 2) & 0x7);
> +
> +	L3_TM_CALIB_DIG19 = mask_read(0xFD40EC4C, 0xFFFFFF18);
> +	L3_TM_CALIB_DIG19 = L3_TM_CALIB_DIG19 | ((p_code & 0x3) << 6)
> +	    | 0x20 | 0x4 | ((n_code >> 3) & 0x3);
> +
> +	L3_TM_CALIB_DIG18 = mask_read(0xFD40EC48, 0xFFFFFF0F);
> +	L3_TM_CALIB_DIG18 = L3_TM_CALIB_DIG18 | ((n_code & 0x7) << 5) | 0x10;
> +
> +	L3_TM_CALIB_DIG16 = mask_read(0xFD40EC40, 0xFFFFFFF8);
> +	L3_TM_CALIB_DIG16 = L3_TM_CALIB_DIG16 | ((r_code >> 1) & 0x7);
> +
> +	L3_TM_CALIB_DIG15 = mask_read(0xFD40EC3C, 0xFFFFFF30);
> +	L3_TM_CALIB_DIG15 = L3_TM_CALIB_DIG15 | ((r_code & 0x1) << 7)
> +	    | 0x40 | 0x8 | ((i_code >> 1) & 0x7);
> +
> +	L3_TM_CALIB_DIG14 = mask_read(0xFD40EC38, 0xFFFFFF3F);
> +	L3_TM_CALIB_DIG14 = L3_TM_CALIB_DIG14 | ((i_code & 0x1) << 7) | 0x40;
> +
> +	Xil_Out32(0xFD40EC50, L3_TM_CALIB_DIG20);
> +	Xil_Out32(0xFD40EC4C, L3_TM_CALIB_DIG19);
> +	Xil_Out32(0xFD40EC48, L3_TM_CALIB_DIG18);
> +	Xil_Out32(0xFD40EC40, L3_TM_CALIB_DIG16);
> +	Xil_Out32(0xFD40EC3C, L3_TM_CALIB_DIG15);
> +	Xil_Out32(0xFD40EC38, L3_TM_CALIB_DIG14);
> +	return maskstatus;
> +}
> +
> +static int init_serdes(void)
> +{
> +	int status = 1;
> +
> +	status &= psu_resetin_init_data();
> +
> +	status &= serdes_fixcal_code();
> +	status &= serdes_enb_coarse_saturation();
> +
> +	status &= psu_serdes_init_data();
> +	status &= psu_resetout_init_data();
> +
> +	return status;
> +}
> +
>   static void init_peripheral(void)
>   {
>   	psu_mask_write(0xFD5F0018, 0x8000001FU, 0x8000001FU);
> @@ -927,6 +1183,7 @@ int psu_init(void)
>   	status &= psu_ddr_init_data();
>   	status &= psu_ddr_phybringup_data();
>   	status &= psu_peripherals_init_data();
> +	status &= init_serdes();

And regarding serdes initialization itsel.
When you do this.

diff --git a/drivers/phy/phy-zynqmp.c b/drivers/phy/phy-zynqmp.c
index d1288bb17f3c..5d2fe0e4991d 100644
--- a/drivers/phy/phy-zynqmp.c
+++ b/drivers/phy/phy-zynqmp.c
@@ -9,6 +9,8 @@
   * Author: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
   */

+#define DEBUG
+
  #include <common.h>
  #include <clk-uclass.h>
  #include <dm.h>


And run it. You will see that actually serdes is initialized already with using 
psgtr driver. It means pretty much serdes code is not needed at all.

ZynqMP> usb start
starting USB...
Bus usb at fe200000: psgtr_phy phy at fd400000: Checking name: ref0
psgtr_phy phy at fd400000: ref0 clock not specified (err -61)
psgtr_phy phy at fd400000: Checking name: ref1
psgtr_phy phy at fd400000: ref1 clock not specified (err -61)
psgtr_phy phy at fd400000: Checking name: ref2
psgtr_phy phy at fd400000: clk rate 26000000
psgtr_phy phy at fd400000: Found rate 3
psgtr_phy phy at fd400000: Checking name: ref3
psgtr_phy phy at fd400000: ref3 clock not specified (err -61)
psgtr_phy phy at fd400000: lane 2 (type 0, protocol 3): init done
psgtr_phy phy at fd400000: Waiting for PLL lock
Register 2000440 NbrPorts 2
Starting the controller
USB XHCI 1.00

If that serdes code is required it is pretty much because there is different 
configuration somewhere else.

With USB3.0 and upstream usb stack I see usb not to stable but I see the same 
behavior when u-boot phy driver is not used and sequence above is used.

Anyway I am definitely interested to get MIO values sorted it out because they 
are not correct and should be fixed and pretty much via pinctrl properties at best.
What we should actually do is to take psu_init and simply remove pin 
configuration for all MIOs which are not defined by spec. That would prove that 
our pinctrl setting is complete.

Tejas: Can you please take a look at it?

Thanks,
Michal




More information about the U-Boot mailing list