From 20fa8382e67c949412e737977d732a5111f82abd Mon Sep 17 00:00:00 2001 From: CTCaer Date: Wed, 27 Aug 2025 15:13:56 +0300 Subject: [PATCH] bdk: hwinit: refactor MBIST WAR & add description The biggest take here is that the split approach of having it in Bootrom and Bootloader is that it's only for boot. Any later powerdown must rerun the WAR for that particular power domain. --- bdk/soc/ccplex.c | 2 +- bdk/soc/hw_init.c | 159 +++++++++++++++++++++++++--------------------- bdk/soc/t210.h | 11 ++-- 3 files changed, 94 insertions(+), 78 deletions(-) diff --git a/bdk/soc/ccplex.c b/bdk/soc/ccplex.c index a5350a50..2b570031 100644 --- a/bdk/soc/ccplex.c +++ b/bdk/soc/ccplex.c @@ -115,7 +115,7 @@ void ccplex_boot_cpu0(u32 entry, bool lock) } // Tighten up the security aperture. - // MC(MC_TZ_SECURITY_CTRL) = 1; + // MC(MC_TZ_SECURITY_CTRL) = TZ_SEC_CTRL_CPU_STRICT_TZ_APERTURE_CHECK; // Clear MSELECT reset. CLOCK(CLK_RST_CONTROLLER_RST_DEV_V_CLR) = BIT(CLK_V_MSELECT); diff --git a/bdk/soc/hw_init.c b/bdk/soc/hw_init.c index 6cb2769a..b69809b1 100644 --- a/bdk/soc/hw_init.c +++ b/bdk/soc/hw_init.c @@ -155,16 +155,34 @@ static void _config_pmc_scratch() PMC(APBDEV_PMC_SECURE_SCRATCH21) |= PMC_FUSE_PRIVATEKEYDISABLE_TZ_STICKY_BIT; } -static void _mbist_workaround() +static void _mbist_workaround_bl() { - // Make sure Audio clocks are enabled before accessing I2S. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); + /* + * DFT MBIST HW Errata for T210. + * RAM Data corruption observed when MBIST_EN from DFT (Tegra X1 Si Errata) + * + * The MBIST_EN signals from the DFT logic can impact the functional logic of + * internal rams after power-on since they are driven by non-resetable flops. + * That can be worked around by enabling and then disabling the related clocks. + * + * The bootrom patches, already handle the LVL2 SLCG war by enabling all clocks + * and all LVL2 CLK overrides (power saving disable). + * The Bootloader then handles the IP block SLCG part and also restores the + * state for the clocks/lvl2 slcg. + * After these, per domain MBIST WAR is needed every time a domain gets + * unpowergated if it was previously powergated. + * + * Affected power domains: all except IRAM and CCPLEX. + */ - // Set mux output to SOR1 clock switch. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) | 0x8000) & 0xFFFFBFFF; - // Enabled PLLD and set csi to PLLD for test pattern generation. - CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= 0x40800000; + // Set mux output to SOR1 clock switch (for VI). + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) & ~BIT(14)) | BIT(15); + // Enable PLLD and set csi to PLLD for test pattern generation (for VI). + CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) |= PLL_BASE_ENABLE | BIT(23); + + // Make sure Audio clocks are enabled before accessing I2S. + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_AHUB); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_APE); // Clear per-clock resets for APE/VIC/HOST1X/DISP1. CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_CLR) = BIT(CLK_Y_APE); @@ -172,78 +190,73 @@ static void _mbist_workaround() CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_CLR) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); usleep(2); - // I2S channels to master and disable SLCG. - I2S(I2S1_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S1_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S2_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S2_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S3_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S3_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S4_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S4_CG) &= ~I2S_CG_SLCG_ENABLE; - I2S(I2S5_CTRL) |= I2S_CTRL_MASTER_EN; - I2S(I2S5_CG) &= ~I2S_CG_SLCG_ENABLE; - - // Set SLCG overrides. - DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= 4; // DSC_SLCG_OVERRIDE. + // Set I2S to master to enable clocks and set SLCG overrides. + for (u32 i2s_idx = 0; i2s_idx < 5; i2s_idx++) + { + I2S(I2S_CTRL + (i2s_idx << 8u)) |= I2S_CTRL_MASTER_EN; + I2S(I2S_CG + (i2s_idx << 8u)) = I2S_CG_SLCG_DISABLE; + } + // Set SLCG overrides for DISPA and VIC. + DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) |= BIT(2); // DSC_SLCG_OVERRIDE. VIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0xFFFFFFFF; + + // Wait a bit for MBIST_EN to get unstuck (1 cycle min). usleep(2); + // Reset SLCG to automatic mode. + // for (u32 i2s_idx = 0; i2s_idx < 5; i2s_idx++) + // I2S(I2S_CG + (i2s_idx << 8u)) = I2S_CG_SLCG_ENABLE; + // DISPLAY_A(_DIREG(DC_COM_DSC_TOP_CTL)) &= ~BIT(2); // DSC_SLCG_OVERRIDE. + // VIC(VIC_THI_SLCG_OVERRIDE_LOW_A) = 0; + // Set per-clock reset for APE/VIC/HOST1X/DISP1. CLOCK(CLK_RST_CONTROLLER_RST_DEV_Y_SET) = BIT(CLK_Y_APE); CLOCK(CLK_RST_CONTROLLER_RST_DEV_L_SET) = BIT(CLK_L_HOST1X) | BIT(CLK_L_DISP1); CLOCK(CLK_RST_CONTROLLER_RST_DEV_X_SET) = BIT(CLK_X_VIC); - // Enable specific clocks and disable all others. + // Disable all unneeded clocks that were enabled in bootrom. // CLK L Devices. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = - BIT(CLK_H_PMC) | - BIT(CLK_H_FUSE); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_H) = BIT(CLK_H_PMC) | + BIT(CLK_H_FUSE); // CLK H Devices. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = - BIT(CLK_L_RTC) | - BIT(CLK_L_TMR) | - BIT(CLK_L_GPIO) | - BIT(CLK_L_BPMP_CACHE_CTRL); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) = BIT(CLK_L_RTC) | + BIT(CLK_L_TMR) | + BIT(CLK_L_GPIO) | + BIT(CLK_L_BPMP_CACHE_CTRL); // CLK U Devices. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = - BIT(CLK_U_CSITE) | - BIT(CLK_U_IRAMA) | - BIT(CLK_U_IRAMB) | - BIT(CLK_U_IRAMC) | - BIT(CLK_U_IRAMD) | - BIT(CLK_U_BPMP_CACHE_RAM); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_U) = BIT(CLK_U_CSITE) | + BIT(CLK_U_IRAMA) | + BIT(CLK_U_IRAMB) | + BIT(CLK_U_IRAMC) | + BIT(CLK_U_IRAMD) | + BIT(CLK_U_BPMP_CACHE_RAM); // CLK V Devices. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = - BIT(CLK_V_MSELECT) | - BIT(CLK_V_APB2APE) | - BIT(CLK_V_SPDIF_DOUBLER) | - BIT(CLK_V_SE); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) = BIT(CLK_V_MSELECT) | + BIT(CLK_V_APB2APE) | + BIT(CLK_V_SPDIF_DOUBLER) | + BIT(CLK_V_SE); // CLK W Devices. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = - BIT(CLK_W_PCIERX0) | - BIT(CLK_W_PCIERX1) | - BIT(CLK_W_PCIERX2) | - BIT(CLK_W_PCIERX3) | - BIT(CLK_W_PCIERX4) | - BIT(CLK_W_PCIERX5) | - BIT(CLK_W_ENTROPY) | - BIT(CLK_W_MC1); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_W) = BIT(CLK_W_PCIERX0) | + BIT(CLK_W_PCIERX1) | + BIT(CLK_W_PCIERX2) | + BIT(CLK_W_PCIERX3) | + BIT(CLK_W_PCIERX4) | + BIT(CLK_W_PCIERX5) | + BIT(CLK_W_ENTROPY) | + BIT(CLK_W_MC1); // CLK X Devices. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = - BIT(CLK_X_MC_CAPA) | - BIT(CLK_X_MC_CBPA) | - BIT(CLK_X_MC_CPU) | - BIT(CLK_X_MC_BBC) | - BIT(CLK_X_GPU) | - BIT(CLK_X_DBGAPB) | - BIT(CLK_X_PLLG_REF); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_X) = BIT(CLK_X_MC_CAPA) | + BIT(CLK_X_MC_CBPA) | + BIT(CLK_X_MC_CPU) | + BIT(CLK_X_MC_BBC) | + BIT(CLK_X_GPU) | + BIT(CLK_X_DBGAPB) | + BIT(CLK_X_PLLG_REF); // CLK Y Devices. - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = - BIT(CLK_Y_MC_CDPA) | - BIT(CLK_Y_MC_CCPA); + CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) = BIT(CLK_Y_MC_CDPA) | + BIT(CLK_Y_MC_CCPA); - // Disable clock gate overrides. + // Reset clock gate overrides to automatic mode. CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRA) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRB) = 0; CLOCK(CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRC) = 0; @@ -252,10 +265,10 @@ static void _mbist_workaround() // Set child clock sources. CLOCK(CLK_RST_CONTROLLER_PLLD_BASE) &= 0x1F7FFFFF; // Disable PLLD and set reference clock and csi clock. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= 0xFFFF3FFF; // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. - CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | 0x80000000; // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_SOR1) &= ~(BIT(15) | BIT(14)); // Set SOR1 to automatic muxing of safe clock (24MHz) or SOR1 clk switch. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_VI) & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X) & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT. + CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) = (CLOCK(CLK_RST_CONTROLLER_CLK_SOURCE_NVENC) & 0x1FFFFFFF) | (4 << 29u); // Set clock source to PLLP_OUT. } static void _config_se_brom() @@ -375,9 +388,9 @@ void hw_init() SYSREG(AHB_AHB_SPARE_REG) &= 0xFFFFFF9F; PMC(APBDEV_PMC_SCRATCH49) &= 0xFFFFFFFC; - // Perform Memory Built-In Self Test WAR if T210. + // Perform the bootloader part of the Memory Built-In Self Test WAR if T210. if (tegra_t210) - _mbist_workaround(); + _mbist_workaround_bl(); // Make sure PLLP_OUT3/4 is set to 408 MHz and enabled. CLOCK(CLK_RST_CONTROLLER_PLLP_OUTB) = 0x30003; @@ -485,11 +498,11 @@ void hw_deinit(bool coreboot, u32 bl_magic) // Reset arbiter. hw_config_arbiter(true); - // Re-enable clocks to Audio Processing Engine as a workaround to hanging. + // Re-enable clocks to Audio Processing Engine as a workaround to rerunning mbist war. if (tegra_t210) { - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= BIT(CLK_V_AHUB); - CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= BIT(CLK_Y_APE); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_V_SET) = BIT(CLK_V_AHUB); + CLOCK(CLK_RST_CONTROLLER_CLK_ENB_Y_SET) = BIT(CLK_Y_APE); } // Do coreboot mitigations. diff --git a/bdk/soc/t210.h b/bdk/soc/t210.h index a95e10cd..938a65e6 100644 --- a/bdk/soc/t210.h +++ b/bdk/soc/t210.h @@ -299,8 +299,10 @@ #define IPATCH_CAM_ENTRIES 12 /*! I2S registers. */ -#define I2S1_CG 0x88 -#define I2S1_CTRL 0xA0 +#define I2S_CG 0x88 +#define I2S_CTRL 0xA0 +#define I2S1_CG I2S_CG +#define I2S1_CTRL I2S_CTRL #define I2S2_CG 0x188 #define I2S2_CTRL 0x1A0 #define I2S3_CG 0x288 @@ -309,8 +311,9 @@ #define I2S4_CTRL 0x3A0 #define I2S5_CG 0x488 #define I2S5_CTRL 0x4A0 -#define I2S_CG_SLCG_ENABLE BIT(0) -#define I2S_CTRL_MASTER_EN BIT(10) +#define I2S_CG_SLCG_DISABLE 0 +#define I2S_CG_SLCG_ENABLE BIT(0) +#define I2S_CTRL_MASTER_EN BIT(10) /*! PWM registers. */ #define PWM_CONTROLLER_PWM_CSR_0 0x00