[RFC PATCH 0/6] Add support for K3 BIST

This is an RFC series that aims to implement a driver for the BIST (Built-In Self Test) module for K3 devices. The BIST driver must ideally support triggering of BIST tests, both PBIST (Memory BIST) and LBIST (Logic BIST) on a core. Both tests are destructive in nature. Please see links [1] and [2] for further information regarding the two.
At boot up, BIST is executed by hardware for the MCU domain automatically as part of HW POST. So BIST has been checked only for the MCU domain, and it makes sense to include our driver for BIST at the MCU R5 SPL stage. The driver can trigger BIST runs for the rest of the cores before loading and running any firmware on the cores.
The general procedure for triggering BIST on a core is: 1. Power on the core under test 2. Trigger the BIST test 3. Reset the core under test
This series, triggers PBIST tests on the MAIN_R5_2_x cores.
This is marked as RFC for a couple of WIP reasons: - the core under test is confirmed to be accessible (powered on) before running the test, and unaccessible after running the test by connecting the debugger to the core, however the firmware calls that check if a core is running or not at A72 U-Boot stage responds as the core is still running. Due to this, before loading or running firmware, an explicit 'stop' needs to be issued by the remoteproc framework (which does not work at the earlier R5 stage as the DM firmware is not up yet). Please see the boot logs to understand. This is under debug. - the driver currently implements all three PBIST tests (PBIST, PBIST failure insertion and PBIST ROM); LBIST is WIP but will be more or less similar to how PBIST has been implemented
Would appreciate reviews/comments on how this driver is modelled.
Boot logs: https://gist.github.com/nehamalcom/63e94dbfc8a9b9fcaba6f45210e20cea
[1] https://software-dl.ti.com/jacinto7/esd/processor-sdk-rtos-jacinto7/latest/e... [2] https://software-dl.ti.com/jacinto7/esd/processor-sdk-rtos-jacinto7/latest/e...
Neha Malcom Francis (6): arm: mach-k3: j784s4: Add clk and power support for MAIN_R5_2_x PBIST arm: dts: k3-j784s4-main: Add PBIST_14 node arm: dts: k3-j784s4-main: Add clock and power domains for MAIN_R5_2_x drivers: misc: k3_bist: Add K3 BIST driver arm: mach-k3: j784s4_init: Trigger BIST configs: j784s4_evm_r5_defconfig: Enable BIST
arch/arm/mach-k3/j784s4/j784s4_init.c | 11 + arch/arm/mach-k3/r5/j784s4/clk-data.c | 13 + arch/arm/mach-k3/r5/j784s4/dev-data.c | 7 + configs/j784s4_evm_r5_defconfig | 2 + drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/k3_bist.c | 507 ++++++++++++++++ drivers/misc/k3_bist_static_data.h | 551 ++++++++++++++++++ dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi | 19 + 9 files changed, 1119 insertions(+) create mode 100644 drivers/misc/k3_bist.c create mode 100644 drivers/misc/k3_bist_static_data.h

Add clock and power domains for MAIN_R5_2_0, MAIN_R5_2_1 and PBIST_14.
Signed-off-by: Neha Malcom Francis n-francis@ti.com --- arch/arm/mach-k3/r5/j784s4/clk-data.c | 13 +++++++++++++ arch/arm/mach-k3/r5/j784s4/dev-data.c | 7 +++++++ 2 files changed, 20 insertions(+)
diff --git a/arch/arm/mach-k3/r5/j784s4/clk-data.c b/arch/arm/mach-k3/r5/j784s4/clk-data.c index 793bcac9324..1a7687d5189 100644 --- a/arch/arm/mach-k3/r5/j784s4/clk-data.c +++ b/arch/arm/mach-k3/r5/j784s4/clk-data.c @@ -82,6 +82,11 @@ static const char * const main_pll_hfosc_sel_out12_parents[] = { "board_0_hfosc1_clk_out", };
+static const char * const main_pll_hfosc_sel_out14_parents[] = { + "gluelogic_hfosc0_clkout", + "board_0_hfosc1_clk_out", +}; + static const char * const main_pll_hfosc_sel_out19_parents[] = { "gluelogic_hfosc0_clkout", "board_0_hfosc1_clk_out", @@ -219,6 +224,7 @@ static const struct clk_data clk_list[] = { CLK_MUX("main_pll_hfosc_sel_out0", main_pll_hfosc_sel_out0_parents, 2, 0x43008080, 0, 1, 0), CLK_MUX("main_pll_hfosc_sel_out1", main_pll_hfosc_sel_out1_parents, 2, 0x43008084, 0, 1, 0), CLK_MUX("main_pll_hfosc_sel_out12", main_pll_hfosc_sel_out12_parents, 2, 0x430080b0, 0, 1, 0), + CLK_MUX("main_pll_hfosc_sel_out14", main_pll_hfosc_sel_out14_parents, 2, 0x430080b8, 0, 1, 0), CLK_MUX("main_pll_hfosc_sel_out19", main_pll_hfosc_sel_out19_parents, 2, 0x430080cc, 0, 1, 0), CLK_MUX("main_pll_hfosc_sel_out2", main_pll_hfosc_sel_out2_parents, 2, 0x43008088, 0, 1, 0), CLK_MUX("main_pll_hfosc_sel_out26_0", main_pll_hfosc_sel_out26_0_parents, 2, 0x430080e8, 0, 1, 0), @@ -246,6 +252,7 @@ static const struct clk_data clk_list[] = { CLK_DIV("pllfracf2_ssmod_16fft_main_1_foutpostdiv_clk_subdiv", "pllfracf2_ssmod_16fft_main_1_foutvcop_clk", 0x681038, 16, 3, 0, CLK_DIVIDER_ONE_BASED), CLK_DIV("pllfracf2_ssmod_16fft_main_1_foutpostdiv_clk", "pllfracf2_ssmod_16fft_main_1_foutpostdiv_clk_subdiv", 0x681038, 24, 3, 0, CLK_DIVIDER_ONE_BASED), CLK_PLL("pllfracf2_ssmod_16fft_main_12_foutvcop_clk", "main_pll_hfosc_sel_out12", 0x68c000, 0), + CLK_PLL("pllfracf2_ssmod_16fft_main_14_foutvcop_clk", "main_pll_hfosc_sel_out14", 0x68e000, 0), CLK_PLL("pllfracf2_ssmod_16fft_main_19_foutvcop_clk", "main_pll_hfosc_sel_out19", 0x693000, 0), CLK_PLL("pllfracf2_ssmod_16fft_main_2_foutvcop_clk", "main_pll_hfosc_sel_out2", 0x682000, 0), CLK_PLL("pllfracf2_ssmod_16fft_main_26_foutvcop_clk", "main_pll_hfosc_sel_out26_0", 0x69a000, 0), @@ -267,6 +274,7 @@ static const struct clk_data clk_list[] = { CLK_DIV("hsdiv0_16fft_main_7_hsdivout0_clk", "pllfracf2_ssmod_16fft_main_7_foutvcop_clk", 0x687080, 0, 7, 0, 0), CLK_DIV("hsdiv0_16fft_main_8_hsdivout0_clk", "pllfracf2_ssmod_16fft_main_8_foutvcop_clk", 0x688080, 0, 7, 0, 0), CLK_DIV("hsdiv1_16fft_main_19_hsdivout0_clk", "pllfracf2_ssmod_16fft_main_19_foutvcop_clk", 0x693080, 0, 7, 0, 0), + CLK_DIV("hsdiv2_16fft_main_14_hsdivout2_clk", "pllfracf2_ssmod_16fft_main_14_foutvcop_clk", 0x68e088, 0, 7, 0, 0), CLK_DIV("hsdiv4_16fft_main_0_hsdivout0_clk", "pllfracf2_ssmod_16fft_main_0_foutvcop_clk", 0x680080, 0, 7, 0, 0), CLK_DIV("hsdiv4_16fft_main_0_hsdivout2_clk", "pllfracf2_ssmod_16fft_main_0_foutvcop_clk", 0x680088, 0, 7, 0, 0), CLK_DIV("hsdiv4_16fft_main_0_hsdivout3_clk", "pllfracf2_ssmod_16fft_main_0_foutvcop_clk", 0x68008c, 0, 7, 0, 0), @@ -397,6 +405,7 @@ static const struct dev_clk soc_dev_clk_data[] = { DEV_CLK(194, 5, "k3_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), DEV_CLK(201, 0, "k3_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), DEV_CLK(201, 1, "k3_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), + DEV_CLK(237, 7, "k3_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), DEV_CLK(243, 0, "j7am_wakeup_16ff_wkup_0_wkup_rcosc_12p5m_clk"), DEV_CLK(243, 1, "gluelogic_hfosc0_clkout"), DEV_CLK(243, 2, "k3_pll_ctrl_wrap_wkup_0_chip_div1_clk_clk"), @@ -405,6 +414,10 @@ static const struct dev_clk soc_dev_clk_data[] = { DEV_CLK(279, 2, "wkup_i2c_mcupll_bypass_out0"), DEV_CLK(279, 3, "hsdiv4_16fft_mcu_1_hsdivout3_clk"), DEV_CLK(279, 4, "gluelogic_hfosc0_clkout"), + DEV_CLK(343, 0, "hsdiv2_16fft_main_14_hsdivout2_clk"), + DEV_CLK(343, 1, "hsdiv2_16fft_main_14_hsdivout2_clk"), + DEV_CLK(344, 0, "hsdiv2_16fft_main_14_hsdivout2_clk"), + DEV_CLK(344, 1, "hsdiv2_16fft_main_14_hsdivout2_clk"), DEV_CLK(392, 0, "usart_programmable_clock_divider_out5"), DEV_CLK(392, 3, "k3_pll_ctrl_wrap_main_0_chip_div1_clk_clk"), DEV_CLK(395, 0, "usart_programmable_clock_divider_out8"), diff --git a/arch/arm/mach-k3/r5/j784s4/dev-data.c b/arch/arm/mach-k3/r5/j784s4/dev-data.c index d66ba8b16e0..843b9a2df36 100644 --- a/arch/arm/mach-k3/r5/j784s4/dev-data.c +++ b/arch/arm/mach-k3/r5/j784s4/dev-data.c @@ -25,6 +25,7 @@ static struct ti_pd soc_pd_list[] = { [5] = PSC_PD(15, &soc_psc_list[2], &soc_pd_list[4]), [6] = PSC_PD(16, &soc_psc_list[2], &soc_pd_list[4]), [7] = PSC_PD(38, &soc_psc_list[2], NULL), + [8] = PSC_PD(39, &soc_psc_list[2], NULL), };
static struct ti_lpsc soc_lpsc_list[] = { @@ -51,6 +52,9 @@ static struct ti_lpsc soc_lpsc_list[] = { [20] = PSC_LPSC(81, &soc_psc_list[2], &soc_pd_list[6], &soc_lpsc_list[18]), [21] = PSC_LPSC(120, &soc_psc_list[2], &soc_pd_list[7], &soc_lpsc_list[22]), [22] = PSC_LPSC(121, &soc_psc_list[2], &soc_pd_list[7], NULL), + [23] = PSC_LPSC(122, &soc_psc_list[2], &soc_pd_list[8], NULL), + [24] = PSC_LPSC(123, &soc_psc_list[2], &soc_pd_list[8], NULL), + [25] = PSC_LPSC(124, &soc_psc_list[2], &soc_pd_list[8], &soc_lpsc_list[24]), };
static struct ti_dev soc_dev_list[] = { @@ -84,6 +88,9 @@ static struct ti_dev soc_dev_list[] = { PSC_DEV(203, &soc_lpsc_list[20]), PSC_DEV(133, &soc_lpsc_list[21]), PSC_DEV(193, &soc_lpsc_list[22]), + PSC_DEV(343, &soc_lpsc_list[23]), + PSC_DEV(344, &soc_lpsc_list[24]), + PSC_DEV(237, &soc_lpsc_list[25]), };
const struct ti_k3_pd_platdata j784s4_pd_platdata = {

On 9/3/2024 5:13 PM, Neha Malcom Francis wrote:
Add clock and power domains for MAIN_R5_2_0, MAIN_R5_2_1 and PBIST_14.
Please keep provision for other R core as well, BIST may be needed in future on those
Signed-off-by: Neha Malcom Francis n-francis@ti.com
arch/arm/mach-k3/r5/j784s4/clk-data.c | 13 +++++++++++++ arch/arm/mach-k3/r5/j784s4/dev-data.c | 7 +++++++ 2 files changed, 20 insertions(+) [..]

Hi Udit,
On 04/09/24 09:49, Kumar, Udit wrote:
On 9/3/2024 5:13 PM, Neha Malcom Francis wrote:
Add clock and power domains for MAIN_R5_2_0, MAIN_R5_2_1 and PBIST_14.
Please keep provision for other R core as well, BIST may be needed in future on those
I was thinking of having this in a "add according to use" basis as there are multiple PBISTs and associated modules/cores and it seems unnecessary to add all this extra data at the R5 SPL stage where only minimal configurations need to be set.
Although by the same logic, I could say that these data and DTS patches should be DONOTMERGE...
Not sure what to do here.
Signed-off-by: Neha Malcom Francis n-francis@ti.com
arch/arm/mach-k3/r5/j784s4/clk-data.c | 13 +++++++++++++ arch/arm/mach-k3/r5/j784s4/dev-data.c | 7 +++++++ 2 files changed, 20 insertions(+) [..]

Add DT node for PBIST_14 that is responsible for triggering the BIST self-tests for the MAIN_R5_2_x cores.
Signed-off-by: Neha Malcom Francis n-francis@ti.com --- dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi index 6a4554c6c9c..5d9b0b6b59d 100644 --- a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi +++ b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi @@ -2255,4 +2255,14 @@ */ }; }; + + bist_mcu14: bist@33c0000 { + compatible = "ti,j784s4-bist"; + reg = <0x00 0x033c0000 0x00 0x400>; + clocks = <&k3_clks 237 7>; + power-domains = <&k3_pds 237 TI_SCI_PD_EXCLUSIVE>; + bootph-pre-ram; + ti,bist-instance = <14>; + cores-under-test = <&main_r5fss2_core0>, <&main_r5fss2_core1>; + }; };

On 9/3/2024 5:13 PM, Neha Malcom Francis wrote:
Add DT node for PBIST_14 that is responsible for triggering the BIST self-tests for the MAIN_R5_2_x cores.
Signed-off-by: Neha Malcom Francis n-francis@ti.com
dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi index 6a4554c6c9c..5d9b0b6b59d 100644 --- a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi +++ b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi @@ -2255,4 +2255,14 @@ */ }; };
- bist_mcu14: bist@33c0000 {
Name shouldn't be mcu, if this is included in main .
Also consider to put this is kernel as well.
compatible = "ti,j784s4-bist";
reg = <0x00 0x033c0000 0x00 0x400>;
clocks = <&k3_clks 237 7>;
power-domains = <&k3_pds 237 TI_SCI_PD_EXCLUSIVE>;
bootph-pre-ram;
ti,bist-instance = <14>;
cores-under-test = <&main_r5fss2_core0>, <&main_r5fss2_core1>;
- }; };

Hi Udit
On 04/09/24 09:52, Kumar, Udit wrote:
On 9/3/2024 5:13 PM, Neha Malcom Francis wrote:
Add DT node for PBIST_14 that is responsible for triggering the BIST self-tests for the MAIN_R5_2_x cores.
Signed-off-by: Neha Malcom Francis n-francis@ti.com
dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi index 6a4554c6c9c..5d9b0b6b59d 100644 --- a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi +++ b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi @@ -2255,4 +2255,14 @@ */ }; };
+ bist_mcu14: bist@33c0000 {
Name shouldn't be mcu, if this is included in main .
Also consider to put this is kernel as well.
Thanks for catching this! Will change it, and yes once the properties needed (based on this RFC review) is decided DTS patch will be sent to kernel first.
+ compatible = "ti,j784s4-bist"; + reg = <0x00 0x033c0000 0x00 0x400>; + clocks = <&k3_clks 237 7>; + power-domains = <&k3_pds 237 TI_SCI_PD_EXCLUSIVE>; + bootph-pre-ram; + ti,bist-instance = <14>; + cores-under-test = <&main_r5fss2_core0>, <&main_r5fss2_core1>; + }; };

Add bootph-pre-ram as well as the clocks and power-domains for MAIN_R5_2_x. This ensures that LPSC sets the appropriate power and clock and allows for BIST to turn the cores on and off for running the self-test at R5 SPL stage.
Signed-off-by: Neha Malcom Francis n-francis@ti.com --- dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi index 5d9b0b6b59d..42dbf3083e1 100644 --- a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi +++ b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi @@ -1897,6 +1897,7 @@ ranges = <0x5900000 0x00 0x5900000 0x20000>, <0x5a00000 0x00 0x5a00000 0x20000>; power-domains = <&k3_pds 338 TI_SCI_PD_EXCLUSIVE>; + bootph-pre-ram;
main_r5fss2_core0: r5f@5900000 { compatible = "ti,j721s2-r5f"; @@ -1911,6 +1912,10 @@ ti,atcm-enable = <1>; ti,btcm-enable = <1>; ti,loczrama = <1>; + clocks = <&k3_clks 343 0>; + power-domains = <&k3_pds 343 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 343 0>; + bootph-pre-ram; };
main_r5fss2_core1: r5f@5a00000 { @@ -1926,6 +1931,10 @@ ti,atcm-enable = <1>; ti,btcm-enable = <1>; ti,loczrama = <1>; + clocks = <&k3_clks 344 0>; + power-domains = <&k3_pds 344 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 344 0>; + bootph-pre-ram; }; };

On 9/3/2024 5:13 PM, Neha Malcom Francis wrote:
Add bootph-pre-ram as well as the clocks and power-domains for MAIN_R5_2_x. This ensures that LPSC sets the appropriate power and clock and allows for BIST to turn the cores on and off for running the self-test at R5 SPL stage.
Signed-off-by: Neha Malcom Francis n-francis@ti.com
dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi index 5d9b0b6b59d..42dbf3083e1 100644 --- a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi +++ b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi @@ -1897,6 +1897,7 @@ ranges = <0x5900000 0x00 0x5900000 0x20000>, <0x5a00000 0x00 0x5a00000 0x20000>; power-domains = <&k3_pds 338 TI_SCI_PD_EXCLUSIVE>;
bootph-pre-ram;
main_r5fss2_core0: r5f@5900000 { compatible = "ti,j721s2-r5f";
@@ -1911,6 +1912,10 @@ ti,atcm-enable = <1>; ti,btcm-enable = <1>; ti,loczrama = <1>;
clocks = <&k3_clks 343 0>;
power-domains = <&k3_pds 343 TI_SCI_PD_EXCLUSIVE>;
assigned-clocks = <&k3_clks 343 0>;
bootph-pre-ram;
};
main_r5fss2_core1: r5f@5a00000 {
@@ -1926,6 +1931,10 @@ ti,atcm-enable = <1>; ti,btcm-enable = <1>; ti,loczrama = <1>;
clocks = <&k3_clks 344 0>;
power-domains = <&k3_pds 344 TI_SCI_PD_EXCLUSIVE>;
assigned-clocks = <&k3_clks 344 0>;
bootph-pre-ram;
Only leaf nodes should be ok with bootph-pre-ram
};
};

On 04/09/24 09:55, Kumar, Udit wrote:
On 9/3/2024 5:13 PM, Neha Malcom Francis wrote:
Add bootph-pre-ram as well as the clocks and power-domains for MAIN_R5_2_x. This ensures that LPSC sets the appropriate power and clock and allows for BIST to turn the cores on and off for running the self-test at R5 SPL stage.
Signed-off-by: Neha Malcom Francis n-francis@ti.com
dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi index 5d9b0b6b59d..42dbf3083e1 100644 --- a/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi +++ b/dts/upstream/src/arm64/ti/k3-j784s4-main.dtsi @@ -1897,6 +1897,7 @@ ranges = <0x5900000 0x00 0x5900000 0x20000>, <0x5a00000 0x00 0x5a00000 0x20000>; power-domains = <&k3_pds 338 TI_SCI_PD_EXCLUSIVE>; + bootph-pre-ram; main_r5fss2_core0: r5f@5900000 { compatible = "ti,j721s2-r5f"; @@ -1911,6 +1912,10 @@ ti,atcm-enable = <1>; ti,btcm-enable = <1>; ti,loczrama = <1>; + clocks = <&k3_clks 343 0>; + power-domains = <&k3_pds 343 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 343 0>; + bootph-pre-ram; }; main_r5fss2_core1: r5f@5a00000 { @@ -1926,6 +1931,10 @@ ti,atcm-enable = <1>; ti,btcm-enable = <1>; ti,loczrama = <1>; + clocks = <&k3_clks 344 0>; + power-domains = <&k3_pds 344 TI_SCI_PD_EXCLUSIVE>; + assigned-clocks = <&k3_clks 344 0>; + bootph-pre-ram;
Only leaf nodes should be ok with bootph-pre-ram
Will change this, thanks!
}; };

Add a driver for the BIST module which currently includes support for BIST IPs that trigger PBIST (Memory BIST).
Signed-off-by: Neha Malcom Francis n-francis@ti.com --- drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/k3_bist.c | 507 ++++++++++++++++++++++++++ drivers/misc/k3_bist_static_data.h | 551 +++++++++++++++++++++++++++++ 4 files changed, 1067 insertions(+) create mode 100644 drivers/misc/k3_bist.c create mode 100644 drivers/misc/k3_bist_static_data.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..8e28a93d74c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -664,6 +664,14 @@ config ESM_K3 help Support ESM (Error Signaling Module) on TI K3 SoCs.
+config K3_BIST + bool "Enable K3 BIST driver" + depends on ARCH_K3 + help + Support BIST (Built-In Self Test) module on TI K3 SoCs. This driver + supports running both PBIST (Memory BIST) and LBIST (Logic BIST) on + a region or IP in the SoC. + config MICROCHIP_FLEXCOM bool "Enable Microchip Flexcom driver" depends on MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e53d52c47b3..15c5c4810dd 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o obj-$(CONFIG_K3_AVS0) += k3_avs.o obj-$(CONFIG_ESM_K3) += k3_esm.o +obj-$(CONFIG_K3_BIST) += k3_bist.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o diff --git a/drivers/misc/k3_bist.c b/drivers/misc/k3_bist.c new file mode 100644 index 00000000000..a4728376b73 --- /dev/null +++ b/drivers/misc/k3_bist.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Texas Instruments' BIST (Built-In Self-Test) driver + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * Neha Malcom Francis n-francis@ti.com + * + */ + +#include <dm.h> +#include <errno.h> +#include <clk.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <asm/arch/hardware.h> +#include <linux/soc/ti/ti_sci_protocol.h> +#include <remoteproc.h> +#include <power-domain.h> + +#include "k3_bist_static_data.h" + +/* PBIST Timeout Value */ +#define PBIST_MAX_TIMEOUT_VALUE 100000000 + +/** + * struct k3_bist_privdata - K3 BIST structure + * @dev: device pointer + * @base: base of register set + * @instance: PBIST instance number + * @intr_num: corresponding interrupt ID of the PBIST instance + */ +struct k3_bist_privdata { + struct udevice *dev; + void *base; + u32 instance; + u32 intr_num; +}; + +static struct k3_bist_privdata *k3_bist_priv; + +/** + * pbist_run_post_pbist_check() - Check POST results + * + * Function to check whether HW Power-On Self Test, i.e. POST has run + * successfully on the MCU domain. + * + * Return: 0 if all went fine, else corresponding error. + */ +int pbist_run_post_pbist_check(void) +{ + bool is_done, timed_out; + u32 mask; + u32 post_reg_val, shift; + + /* Read HW POST status register */ + post_reg_val = readl(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT); + + /* Check if HW POST PBIST was performed */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_DONE_SHIFT; + is_done = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false; + + if (!is_done) { + /* HW POST: PBIST not completed, check if it timed out */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_TIMEOUT_SHIFT; + timed_out = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false; + + if (!timed_out) { + debug("%s: PBIST was not performed at all on this device for this core\n", + __func__); + return -EINVAL; + } else { + debug("%s: PBIST was attempted but timed out for this section\n", __func__); + return -ETIMEDOUT; + } + } else { + /* HW POST: PBIST was completed on this device, check the result */ + mask = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_FAIL_MASK; + + if ((post_reg_val & mask) != 0) { + debug("%s: PBIST was completed, but the test failed\n", __func__); + return -EINVAL; + } else { + debug("%s: HW POST PBIST completed, test passed\n", __func__); + } + } + + return 0; +} + +/** + * core_get_by_index() - Configure processor to correct state + * + * Function to configure processor under test to correct state for SW-initiated + * PBIST + * @dev: BIST device + * @index: corresponding index of the core in the cores-under-test list + * @turnoff: true if core is needed to be turned off + * + * Return: 0 if all went fine, else corresponding error. + */ +int core_get_by_index(struct udevice *dev, int index, bool turnoff) +{ + struct ofnode_phandle_args args; + int ret; + struct udevice *dev_core; + + ret = dev_read_phandle_with_args(dev, "cores-under-test", NULL, 0, index, &args); + if (ret) { + debug("%s: dev_read_phandle_with_args failed: %d\n", __func__, + ret); + return ret; + } + ret = uclass_get_device_by_ofnode(UCLASS_REMOTEPROC, args.node, &dev_core); + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed: %d\n", + __func__, ret); + return ret; + } + + if (turnoff) { + struct power_domain pwrdmn; + struct clk fclk; + + ret = power_domain_get_by_index(dev_core, &pwrdmn, 0); + if (ret) { + dev_err(dev, "failed to get power domain for the core %d\n", ret); + return ret; + } + + ret = clk_get_by_index(dev_core, 0, &fclk); + if (ret) { + dev_err(dev, "failed to get clock for the core %d\n", ret); + return ret; + } + + ret = power_domain_off(&pwrdmn); + if (ret) { + dev_err(dev, "failed to power OFF the core %d\n", ret); + return ret; + } + + ret = power_domain_free(&pwrdmn); + if (ret) { + dev_err(dev, "failed to free the core %d\n", ret); + return ret; + } + ret = clk_disable(&fclk); + if (ret) { + dev_err(dev, "failed to disable clock of the core %d\n", ret); + return ret; + } + } + return 0; +} + +/** + * pbist_self_test() - Run PBIST_TEST on specified cores + * @config: pbist_config structure for PBIST test + * + * Function to run PBIST_TEST + * + * Return: 0 if all went fine, else corresponding error. + */ +int pbist_self_test(struct pbist_config *config) +{ + struct udevice *dev = k3_bist_priv->dev; + void *base = k3_bist_priv->base; + u32 intr_num = k3_bist_priv->intr_num; + bool test_result = true; + + /* Turns on PBIST clock in PBIST ACTivate register */ + writel(PBIST_PACT_PACT_MASK, base + PBIST_PACT); + + /* Set Margin mode register for Test mode */ + writel(PBIST_TEST_MODE, base + PBIST_MARGIN_MODE); + + /* Zero out Loop counter 0 */ + writel(0x0, base + PBIST_L0); + + /* Set algorithm bitmap */ + writel(config->algorithms_bit_map, base + PBIST_ALGO); + + /* Set Memory group bitmap */ + writel(config->memory_groups_bit_map, base + PBIST_RINFO); + + /* Zero out override register */ + writel(config->override, base + PBIST_OVER); + + /* Set Scramble value - 64 bit*/ + writel(config->scramble_value_lo, base + PBIST_SCR_LO); + writel(config->scramble_value_hi, base + PBIST_SCR_HI); + + /* Set DLR register for ROM based testing and Config Access */ + writel(PBIST_DLR_DLR0_ROM_MASK + | PBIST_DLR_DLR0_CAM_MASK, base + PBIST_DLR); + + udelay(1000); + + u32 timeout_count = 0; + + while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ; + + if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev); + } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + } + + writel(0xffffffff, VIM_STS(intr_num)); + + return 0; +} + +/** + * pbist_neg_self_test() - Run PBIST_negTEST on specified cores + * @config: pbist_config_neg structure for PBIST negative test + * + * Function to run PBIST failure insertion test + * + * Return: 0 if all went fine, else corresponding error. + */ +int pbist_neg_self_test(struct pbist_config_neg *config) +{ + struct udevice *dev = k3_bist_priv->dev; + void *base = k3_bist_priv->base; + u32 intr_num = k3_bist_priv->intr_num; + bool test_result = true; + + /* Turns on PBIST clock in PBIST ACTivate register */ + writel(PBIST_PACT_PACT_MASK, base + PBIST_PACT); + + /* Set Margin mode register for Test mode */ + writel(PBIST_FAILURE_INSERTION_TEST_MODE, base + PBIST_MARGIN_MODE); + + /* Zero out Loop counter 0 */ + writel(0x0, base + PBIST_L0); + + /* Set DLR register */ + writel(0x10, base + PBIST_DLR); + + /* Set Registers*/ + writel(0x00000001, base + PBIST_RF0L); + writel(0x00003123, base + PBIST_RF0U); + writel(0x0513FC02, base + PBIST_RF1L); + writel(0x00000002, base + PBIST_RF1U); + writel(0x00000003, base + PBIST_RF2L); + writel(0x00000000, base + PBIST_RF2U); + writel(0x00000004, base + PBIST_RF3L); + writel(0x00000028, base + PBIST_RF3U); + writel(0x64000044, base + PBIST_RF4L); + writel(0x00000000, base + PBIST_RF4U); + writel(0x0006A006, base + PBIST_RF5L); + writel(0x00000000, base + PBIST_RF5U); + writel(0x00000007, base + PBIST_RF6L); + writel(0x0000A0A0, base + PBIST_RF6U); + writel(0x00000008, base + PBIST_RF7L); + writel(0x00000064, base + PBIST_RF7U); + writel(0x00000009, base + PBIST_RF8L); + writel(0x0000A5A5, base + PBIST_RF8U); + writel(0x0000000A, base + PBIST_RF9L); + writel(0x00000079, base + PBIST_RF9U); + writel(0x00000000, base + PBIST_RF10L); + writel(0x00000001, base + PBIST_RF10U); + writel(0xAAAAAAAA, base + PBIST_D); + writel(0xAAAAAAAA, base + PBIST_E); + + writel(config->CA2, base + PBIST_CA2); + writel(config->CL0, base + PBIST_CL0); + writel(config->CA3, base + PBIST_CA3); + writel(config->I0, base + PBIST_I0); + writel(config->CL1, base + PBIST_CL1); + writel(config->I3, base + PBIST_I3); + writel(config->I2, base + PBIST_I2); + writel(config->CL2, base + PBIST_CL2); + writel(config->CA1, base + PBIST_CA1); + writel(config->CA0, base + PBIST_CA0); + writel(config->CL3, base + PBIST_CL3); + writel(config->I1, base + PBIST_I1); + writel(config->RAMT, base + PBIST_RAMT); + writel(config->CSR, base + PBIST_CSR); + writel(config->CMS, base + PBIST_CMS); + + writel(0x00000009, base + PBIST_STR); + + /* Start PBIST */ + writel(0x00000001, base + PBIST_STR); + + udelay(1000); + + u32 timeout_count = 0; + + while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ; + + if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev); + } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + } + + writel(0xffffffff, VIM_STS(intr_num)); + + return 0; +} + +/** + * pbist_rom_self_test() - Run PBIST_ROM_TEST on specified cores + * @config: pbist_config_rom structure for PBIST negative test + * + * Function to run PBIST test of ROM + * + * Return: 0 if all went fine, else corresponding error. + */ +int pbist_rom_self_test(struct pbist_config_rom *config) +{ + struct udevice *dev = k3_bist_priv->dev; + void *base = k3_bist_priv->base; + u32 intr_num = k3_bist_priv->intr_num; + bool test_result = true; + + /* Turns on PBIST clock in PBIST ACTivate register */ + writel(0x1, base + PBIST_PACT); + + /* Set Margin mode register for Test mode */ + writel(0xf, base + PBIST_MARGIN_MODE); + + /* Zero out Loop counter 0 */ + writel(0x0, base + PBIST_L0); + + /* Set DLR register */ + writel(0x310, base + PBIST_DLR); + + /* Set Registers*/ + writel(0x00000001, base + PBIST_RF0L); + writel(0x00003123, base + PBIST_RF0U); + writel(0x7A400183, base + PBIST_RF1L); + writel(0x00000060, base + PBIST_RF1U); + writel(0x00000184, base + PBIST_RF2L); + writel(0x00000000, base + PBIST_RF2U); + writel(0x7B600181, base + PBIST_RF3L); + writel(0x00000061, base + PBIST_RF3U); + writel(0x00000000, base + PBIST_RF4L); + writel(0x00000000, base + PBIST_RF4U); + + writel(config->D, base + PBIST_D); + writel(config->E, base + PBIST_E); + writel(config->CA2, base + PBIST_CA2); + writel(config->CL0, base + PBIST_CL0); + writel(config->CA3, base + PBIST_CA3); + writel(config->I0, base + PBIST_I0); + writel(config->CL1, base + PBIST_CL1); + writel(config->I3, base + PBIST_I3); + writel(config->I2, base + PBIST_I2); + writel(config->CL2, base + PBIST_CL2); + writel(config->CA1, base + PBIST_CA1); + writel(config->CA0, base + PBIST_CA0); + writel(config->CL3, base + PBIST_CL3); + writel(config->I1, base + PBIST_I1); + writel(config->RAMT, base + PBIST_RAMT); + writel(config->CSR, base + PBIST_CSR); + writel(config->CMS, base + PBIST_CMS); + + writel(0x00000009, base + PBIST_STR); + + /* Start PBIST */ + writel(0x00000001, base + PBIST_STR); + + udelay(1000); + + u32 timeout_count = 0; + + while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ; + + if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev); + } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + } + + writel(0xffffffff, VIM_STS(intr_num)); + + return 0; +} + +/** + * k3_bist_probe() - Basic probe + * @dev: corresponding BIST device + * + * Parses BIST info from device tree, and configures the module accordingly. + * Return: 0 if all goes good, else appropriate error message. + */ +static int k3_bist_probe(struct udevice *dev) +{ + int ret = 0, num_runs, i, j; + struct k3_bist_privdata *priv = dev_get_priv(dev); + struct pbist_inst_info *info; + + debug("%s(dev=%p)\n", __func__, dev); + + priv = dev_get_priv(dev); + priv->dev = dev; + + k3_bist_priv = priv; + + priv->base = dev_remap_addr_index(dev, 0); + if (!priv->base) + return -ENODEV; + + ret = dev_read_u32(dev, "ti,bist-instance", &priv->instance); + if (!priv->instance) + return -ENODEV; + + switch (priv->instance) { + case PBIST14_INSTANCE: + info = &pbist14_inst_info; + priv->intr_num = info->intr_num; + break; + default: + dev_err(dev, "%s: PBIST instance %d not supported\n", __func__, priv->instance); + return -ENODEV; + }; + + /* Probe the cores under test */ + for (i = 0; ; i++) { + ret = core_get_by_index(dev, i, false); + if (ret) + break; + } + + if (!i) { + dev_err(dev, "%s: Acquiring the core failed. ret = %d\n", __func__, ret); + return ret; + } + + /* Check whether HW POST successfully completely PBIST on the MCU domain */ + ret = pbist_run_post_pbist_check(); + if (ret) { + dev_err(dev, "HW POST failed to run successfully %d\n", ret); + return ret; + } + + /* Run PBIST test */ + num_runs = info->num_pbist_runs; + + for (j = 0; j < num_runs; j++) { + ret = pbist_self_test(&info->pbist_config_run[j]); + if (ret) { + dev_err(dev, "failed to run PBIST test %d\n", ret); + return ret; + } + } + + /* Run PBIST failure insertion test */ + ret = pbist_neg_self_test(&info->pbist_neg_config_run); + if (ret) { + dev_err(dev, "failed to run PBIST negative test %d\n", ret); + return ret; + } + + /* Run PBIST test on ROM */ + num_runs = info->num_pbist_rom_test_runs; + + for (j = 0; j < num_runs; j++) { + ret = pbist_rom_self_test(&info->pbist_rom_test_config_run[j]); + if (ret) { + dev_err(dev, "failed to run ROM PBIST test %d\n", ret); + return ret; + } + } + + /* Power off cores under test */ + while (i--) { + ret = core_get_by_index(dev, i, true); + if (ret) + break; + } + + if (i) { + dev_err(dev, "%s: Stopping the core failed. ret = %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static const struct udevice_id k3_bist_ids[] = { + { .compatible = "ti,j784s4-bist" }, + {} +}; + +U_BOOT_DRIVER(k3_bist) = { + .name = "k3_bist", + .of_match = k3_bist_ids, + .id = UCLASS_MISC, + .probe = k3_bist_probe, + .priv_auto = sizeof(struct k3_bist_privdata), +}; diff --git a/drivers/misc/k3_bist_static_data.h b/drivers/misc/k3_bist_static_data.h new file mode 100644 index 00000000000..f30fb7935b6 --- /dev/null +++ b/drivers/misc/k3_bist_static_data.h @@ -0,0 +1,551 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Static Data for Texas Instruments' BIST (Built-In Self-Test) driver + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + * + */ + +#ifndef __K3_BIST_STATIC_DATA_H +#define __K3_BIST_STATIC_DATA_H + +#define PBIST_MAX_NUM_RUNS 2 +#define NUM_MAX_PBIST_TEST_ROM_RUNS 13 +#define PBIST14_DFT_PBIST_CPU_0_INTR_NUM 311 + +/* VIM Registers */ +#define VIM_STS_BASE 0x40f80404 +#define VIM_RAW_BASE 0x40f80400 + +#define VIM_STS(i) (VIM_STS_BASE + (i) / 32 * 0x20) +#define VIM_RAW(i) (VIM_RAW_BASE + (i) / 32 * 0x20) +#define VIM_RAW_MASK(i) (BIT((i) % 32)) + +/* PBIST Registers and Flags*/ +#define PBIST_RF0L 0x00000000 +#define PBIST_RF1L 0x00000004 +#define PBIST_RF2L 0x00000008 +#define PBIST_RF3L 0x0000000C +#define PBIST_RF4L 0x0000010 +#define PBIST_RF5L 0x0000014 +#define PBIST_RF6L 0x0000018 +#define PBIST_RF7L 0x000001C +#define PBIST_RF8L 0x0000020 +#define PBIST_RF9L 0x0000024 +#define PBIST_RF10L 0x0000028 +#define PBIST_RF11L 0x000002C +#define PBIST_RF12L 0x0000030 +#define PBIST_RF13L 0x0000034 +#define PBIST_RF14L 0x0000038 +#define PBIST_RF15L 0x000003C +#define PBIST_RF0U 0x0000040 +#define PBIST_RF1U 0x0000044 +#define PBIST_RF2U 0x0000048 +#define PBIST_RF3U 0x000004C +#define PBIST_RF4U 0x0000050 +#define PBIST_RF5U 0x0000054 +#define PBIST_RF6U 0x0000058 +#define PBIST_RF7U 0x000005C +#define PBIST_RF8U 0x0000060 +#define PBIST_RF9U 0x0000064 +#define PBIST_RF10U 0x0000068 +#define PBIST_RF11U 0x000006C +#define PBIST_RF12U 0x0000070 +#define PBIST_RF13U 0x0000074 +#define PBIST_RF14U 0x0000078 +#define PBIST_RF15U 0x000007C +#define PBIST_A0 0x0000100 +#define PBIST_A1 0x0000104 +#define PBIST_A2 0x0000108 +#define PBIST_A3 0x000010C +#define PBIST_L0 0x0000110 +#define PBIST_L1 0x0000114 +#define PBIST_L2 0x0000118 +#define PBIST_L3 0x000011C +#define PBIST_D 0x0000120 +#define PBIST_E 0x0000124 +#define PBIST_CA0 0x0000130 +#define PBIST_CA1 0x0000134 +#define PBIST_CA2 0x0000138 +#define PBIST_CA3 0x000013C +#define PBIST_CL0 0x0000140 +#define PBIST_CL1 0x0000144 +#define PBIST_CL2 0x0000148 +#define PBIST_CL3 0x000014C +#define PBIST_I0 0x0000150 +#define PBIST_I1 0x0000154 +#define PBIST_I2 0x0000158 +#define PBIST_I3 0x000015C +#define PBIST_RAMT 0x0000160 +#define PBIST_DLR 0x0000164 +#define PBIST_CMS 0x0000168 +#define PBIST_STR 0x000016C +#define PBIST_SCR 0x0000170 +#define PBIST_SCR_LO 0x0000170 +#define PBIST_SCR_HI 0x0000174 +#define PBIST_CSR 0x0000178 +#define PBIST_FDLY 0x000017C +#define PBIST_PACT 0x0000180 +#define PBIST_PID 0x0000184 +#define PBIST_OVER 0x0000188 +#define PBIST_FSPBIST_RF 0x0000190 +#define PBIST_FSRC 0x0000198 +#define PBIST_FSRA 0x00001A0 +#define PBIST_FSRDL0 0x00001A8 +#define PBIST_FSRDL1 0x00001B0 +#define PBIST_MARGIN_MODE 0x00001B4 +#define PBIST_WRENZ 0x00001B8 +#define PBIST_PAGE_PGS 0x00001BC +#define PBIST_ROM 0x00001C0 +#define PBIST_ALGO 0x00001C4 +#define PBIST_RINFO 0x00001C8 + +#define PBIST_MARGIN_MODE_PBIST_DFT_WRITE_MASK 0x00000003 +#define PBIST_MARGIN_MODE_PBIST_DFT_READ_SHIFT 0x00000002 +#define PBIST_MARGIN_MODE_PBIST_DFT_READ_MASK 0x0000000C +#define PBIST_PACT_PACT_MASK 0x00000001 +#define PBIST_DLR_DLR0_ROM_MASK 0x00000004 +#define PBIST_DLR_DLR0_CAM_MASK 0x00000010 +#define PBIST_NOT_DONE 0 +#define PBIST_DONE 1 + +/* PBIST test mode */ +#define PBIST_TEST_MODE (PBIST_MARGIN_MODE_PBIST_DFT_WRITE_MASK \ + | (1 << PBIST_MARGIN_MODE_PBIST_DFT_READ_SHIFT)) + +/* PBIST Failure Insertion test mode */ +#define PBIST_FAILURE_INSERTION_TEST_MODE (PBIST_MARGIN_MODE_PBIST_DFT_WRITE_MASK \ + | PBIST_MARGIN_MODE_PBIST_DFT_READ_MASK) + +/* + * struct pbist_config - Structure for different configuration used for PBIST + * @override: Override value for memory configuration + * @algorithms_bit_map: Bitmap to select algorithms to use for test + * @memory_groups_bit_map: Bitmap to select memory groups to run test on + * @scramble_value_lo: Lower scramble value to be used for test + * @scramble_value_hi: Higher scramble value to be used for test + */ +struct pbist_config { + u32 override; + u32 algorithms_bit_map; + u64 memory_groups_bit_map; + u32 scramble_value_lo; + u32 scramble_value_hi; +}; + +/* + * struct pbist_config_neg - Structure for different configuration used for PBIST + * for the failure insertion test to generate negative result + * @CA0: Failure insertion value for CA0 + * @CA1: Failure insertion value for CA1 + * @CA2: Failure insertion value for CA2 + * @CA3: Failure insertion value for CA3 + * @CL0: Failure insertion value for CL0 + * @CL1: Failure insertion value for CL1 + * @CL2: Failure insertion value for CL2 + * @CL3: Failure insertion value for CL3 + * @CMS: Failure insertion value for CMS + * @CSR: Failure insertion value for CSR + * @I0: Failure insertion value for I0 + * @I1: Failure insertion value for I1 + * @I2: Failure insertion value for I2 + * @I3: Failure insertion value for I3 + * @RAMT: Failure insertion value for RAMT + */ +struct pbist_config_neg { + u32 CA0; + u32 CA1; + u32 CA2; + u32 CA3; + u32 CL0; + u32 CL1; + u32 CL2; + u32 CL3; + u32 CMS; + u32 CSR; + u32 I0; + u32 I1; + u32 I2; + u32 I3; + u32 RAMT; +}; + +/* + * struct pbist_config_neg - Structure for different configuration used for PBIST + * test of ROM + * @D: ROM test value for D + * @E: ROM test value for E + * @CA2: ROM test value for CA2 + * @CL0: ROM test value for CL0 + * @CA3: ROM test value for CA3 + * @I0: ROM test value for I0 + * @CL1: ROM test value for CL1 + * @I3: ROM test value for I3 + * @I2: ROM test value for I2 + * @CL2: ROM test value for CL2 + * @CA1: ROM test value for CA1 + * @CA0: ROM test value for CA0 + * @CL3: ROM test value for CL3 + * @I1: ROM test value for I1 + * @RAMT: ROM test value for RAMT + * @CSR: ROM test value for CSR + * @CMS: ROM test value for CMS + */ +struct pbist_config_rom { + u32 D; + u32 E; + u32 CA2; + u32 CL0; + u32 CA3; + u32 I0; + u32 CL1; + u32 I3; + u32 I2; + u32 CL2; + u32 CA1; + u32 CA0; + u32 CL3; + u32 I1; + u32 RAMT; + u32 CSR; + u32 CMS; +}; + +/* + * struct pbist_inst_info - Structure for different configuration used for PBIST + * @num_pbist_runs: Number of runs of PBIST test + * @intr_num: Interrupt number triggered by this PBIST instance to MCU R5 VIM + * @pbist_config_run: Configuration for PBIST test + * @pbist_neg_config_run: Configuration for PBIST negative test + * @num_pbist_rom_test_runs: Number of runs of PBIST test on ROM + * @pbist_rom_test_config_run: Configuration for PBIST test on ROM + */ +struct pbist_inst_info { + u32 num_pbist_runs; + u32 intr_num; + struct pbist_config pbist_config_run[PBIST_MAX_NUM_RUNS]; + struct pbist_config_neg pbist_neg_config_run; + u32 num_pbist_rom_test_runs; + struct pbist_config_rom pbist_rom_test_config_run[NUM_MAX_PBIST_TEST_ROM_RUNS]; +}; + +#if IS_ENABLED(CONFIG_SOC_K3_J784S4) + +/* WKUP CTRL MMR Registers */ +#define WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT 0x0000C2C0 +#define WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_DONE_SHIFT 0x00000008 +#define WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_TIMEOUT_SHIFT 0x00000009 +#define WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_FAIL_MASK 0x00008000 + +/* Properties of PBIST instances in: PBIST14 */ +#define PBIST14_INSTANCE 14 +#define PBIST14_NUM_TEST_VECTORS 0x1 +#define PBIST14_ALGO_BITMAP_0 0x00000003 +#define PBIST14_MEM_BITMAP_0 0x000CCCCC +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CA0 0x00000000 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CA1 0x000001FF +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CA2 0x000001FF +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CA3 0x00000000 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CL0 0x0000007F +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CL1 0x00000003 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CL2 0x00000008 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CL3 0x000001FF +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CMS 0x00000000 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_CSR 0x20000000 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_I0 0x00000001 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_I1 0x00000004 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_I2 0x00000008 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_I3 0x00000000 +#define PBIST14_FAIL_INSERTION_TEST_VECTOR_RAMT 0x011D2528 + +static struct pbist_inst_info pbist14_inst_info = { + /* Main Pulsar 2 Instance 1 or MAIN_R52_x */ + .num_pbist_runs = 1, + .intr_num = PBIST14_DFT_PBIST_CPU_0_INTR_NUM, + .pbist_config_run = { + { + .override = 0, + .algorithms_bit_map = PBIST14_ALGO_BITMAP_0, + .memory_groups_bit_map = PBIST14_MEM_BITMAP_0, + .scramble_value_lo = 0x76543210, + .scramble_value_hi = 0xFEDCBA98, + }, + { + .override = 0, + .algorithms_bit_map = 0, + .memory_groups_bit_map = 0, + .scramble_value_lo = 0, + .scramble_value_hi = 0, + }, + }, + .pbist_neg_config_run = { + .CA0 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CA0, + .CA1 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CA1, + .CA2 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CA2, + .CA3 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CA3, + .CL0 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CL0, + .CL1 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CL1, + .CL2 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CL2, + .CL3 = PBIST14_FAIL_INSERTION_TEST_VECTOR_CL3, + .CMS = PBIST14_FAIL_INSERTION_TEST_VECTOR_CMS, + .CSR = PBIST14_FAIL_INSERTION_TEST_VECTOR_CSR, + .I0 = PBIST14_FAIL_INSERTION_TEST_VECTOR_I0, + .I1 = PBIST14_FAIL_INSERTION_TEST_VECTOR_I1, + .I2 = PBIST14_FAIL_INSERTION_TEST_VECTOR_I2, + .I3 = PBIST14_FAIL_INSERTION_TEST_VECTOR_I3, + .RAMT = PBIST14_FAIL_INSERTION_TEST_VECTOR_RAMT + }, + .num_pbist_rom_test_runs = 1, + .pbist_rom_test_config_run = { + { + .D = 0xF412605Eu, + .E = 0xF412605Eu, + .CA2 = 0x7FFFu, + .CL0 = 0x3FFu, + .CA3 = 0x0u, + .I0 = 0x1u, + .CL1 = 0x1Fu, + .I3 = 0x0u, + .I2 = 0xEu, + .CL2 = 0xEu, + .CA1 = 0x7FFFu, + .CA0 = 0x0u, + .CL3 = 0x7FFFu, + .I1 = 0x20u, + .RAMT = 0x08002020u, + .CSR = 0x00000001u, + .CMS = 0x01u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + { + .D = 0x0u, + .E = 0x0u, + .CA2 = 0x0u, + .CL0 = 0x0u, + .CA3 = 0x0u, + .I0 = 0x0u, + .CL1 = 0x0u, + .I3 = 0x0u, + .I2 = 0x0u, + .CL2 = 0x0u, + .CA1 = 0x0u, + .CA0 = 0x0u, + .CL3 = 0x0u, + .I1 = 0x0u, + .RAMT = 0x0u, + .CSR = 0x0u, + .CMS = 0x0u + }, + }, +}; + +#endif /* CONFIG_SOC_K3_J784S4 */ +#endif /* __TI_SCI_STATIC_DATA_H */

On 9/3/2024 5:14 PM, Neha Malcom Francis wrote:
Add a driver for the BIST module which currently includes support for BIST IPs that trigger PBIST (Memory BIST).
Signed-off-by: Neha Malcom Francis n-francis@ti.com
drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/k3_bist.c | 507 ++++++++++++++++++++++++++ drivers/misc/k3_bist_static_data.h | 551 +++++++++++++++++++++++++++++ 4 files changed, 1067 insertions(+) create mode 100644 drivers/misc/k3_bist.c create mode 100644 drivers/misc/k3_bist_static_data.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..8e28a93d74c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -664,6 +664,14 @@ config ESM_K3 help Support ESM (Error Signaling Module) on TI K3 SoCs.
+config K3_BIST
- bool "Enable K3 BIST driver"
- depends on ARCH_K3
- help
Support BIST (Built-In Self Test) module on TI K3 SoCs. This driver
supports running both PBIST (Memory BIST) and LBIST (Logic BIST) on
a region or IP in the SoC.
- config MICROCHIP_FLEXCOM bool "Enable Microchip Flexcom driver" depends on MISC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e53d52c47b3..15c5c4810dd 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o obj-$(CONFIG_K3_AVS0) += k3_avs.o obj-$(CONFIG_ESM_K3) += k3_esm.o +obj-$(CONFIG_K3_BIST) += k3_bist.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o diff --git a/drivers/misc/k3_bist.c b/drivers/misc/k3_bist.c new file mode 100644 index 00000000000..a4728376b73 --- /dev/null +++ b/drivers/misc/k3_bist.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Texas Instruments' BIST (Built-In Self-Test) driver
- Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
Neha Malcom Francis <n-francis@ti.com>
- */
+#include <dm.h> +#include <errno.h> +#include <clk.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <asm/arch/hardware.h> +#include <linux/soc/ti/ti_sci_protocol.h> +#include <remoteproc.h> +#include <power-domain.h>
In general, few macro's name are too long
many places hard-coded values are used, please consider to move to macro
driver looks to be j784s4 specific including header files ,
please see, if we can make this generic driver.
+#include "k3_bist_static_data.h"
+/* PBIST Timeout Value */ +#define PBIST_MAX_TIMEOUT_VALUE 100000000
+/**
- struct k3_bist_privdata - K3 BIST structure
- @dev: device pointer
- @base: base of register set
- @instance: PBIST instance number
- @intr_num: corresponding interrupt ID of the PBIST instance
- */
+struct k3_bist_privdata {
- struct udevice *dev;
- void *base;
- u32 instance;
- u32 intr_num;
+};
+static struct k3_bist_privdata *k3_bist_priv;
+/**
- pbist_run_post_pbist_check() - Check POST results
- Function to check whether HW Power-On Self Test, i.e. POST has run
- successfully on the MCU domain.
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_run_post_pbist_check(void)
Please consider to rename function name as per description above something like
check_pbist_results_of_mcu_domain,, if you agree
Also give more context, I believe, ROM runs BIST on MCU domain, Please consider to mention, if you want
+{
- bool is_done, timed_out;
- u32 mask;
- u32 post_reg_val, shift;
- /* Read HW POST status register */
- post_reg_val = readl(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT);
- /* Check if HW POST PBIST was performed */
- shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_DONE_SHIFT;
- is_done = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
- if (!is_done) {
/* HW POST: PBIST not completed, check if it timed out */
shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_TIMEOUT_SHIFT;
Too long macro name
timed_out = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
if (!timed_out) {
debug("%s: PBIST was not performed at all on this device for this core\n",
__func__);
return -EINVAL;
This is error no ? , move to dev_err instead of debug
} else {
debug("%s: PBIST was attempted but timed out for this section\n", __func__);
return -ETIMEDOUT;
This is error no ? , move to dev_err instead of debug .
What next, reboot SOC or just continue booting in case of error
}
- } else {
/* HW POST: PBIST was completed on this device, check the result */
mask = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_FAIL_MASK;
if ((post_reg_val & mask) != 0) {
debug("%s: PBIST was completed, but the test failed\n", __func__);
return -EINVAL;
} else {
debug("%s: HW POST PBIST completed, test passed\n", __func__);
}
- }
- return 0;
+}
+/**
- core_get_by_index() - Configure processor to correct state
Two operation here. please rename if possible
- Function to configure processor under test to correct state for SW-initiated
- PBIST
- @dev: BIST device
- @index: corresponding index of the core in the cores-under-test list
- @turnoff: true if core is needed to be turned off
- Return: 0 if all went fine, else corresponding error.
- */
+int core_get_by_index(struct udevice *dev, int index, bool turnoff) +{
- struct ofnode_phandle_args args;
- int ret;
- struct udevice *dev_core;
- ret = dev_read_phandle_with_args(dev, "cores-under-test", NULL, 0, index, &args);
- if (ret) {
debug("%s: dev_read_phandle_with_args failed: %d\n", __func__,
ret);
return ret;
- }
- ret = uclass_get_device_by_ofnode(UCLASS_REMOTEPROC, args.node, &dev_core);
- if (ret) {
debug("%s: uclass_get_device_by_of_offset failed: %d\n",
__func__, ret);
return ret;
- }
- if (turnoff) {
struct power_domain pwrdmn;
struct clk fclk;
isn't some tisci call are ok to turn off the CPUs.
ret = power_domain_get_by_index(dev_core, &pwrdmn, 0);
if (ret) {
dev_err(dev, "failed to get power domain for the core %d\n", ret);
return ret;
}
ret = clk_get_by_index(dev_core, 0, &fclk);
if (ret) {
dev_err(dev, "failed to get clock for the core %d\n", ret);
return ret;
}
ret = power_domain_off(&pwrdmn);
if (ret) {
dev_err(dev, "failed to power OFF the core %d\n", ret);
return ret;
}
ret = power_domain_free(&pwrdmn);
if (ret) {
dev_err(dev, "failed to free the core %d\n", ret);
return ret;
}
ret = clk_disable(&fclk);
if (ret) {
dev_err(dev, "failed to disable clock of the core %d\n", ret);
return ret;
}
- }
- return 0;
+}
+/**
- pbist_self_test() - Run PBIST_TEST on specified cores
- @config: pbist_config structure for PBIST test
- Function to run PBIST_TEST
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_self_test(struct pbist_config *config) +{
- struct udevice *dev = k3_bist_priv->dev;
- void *base = k3_bist_priv->base;
- u32 intr_num = k3_bist_priv->intr_num;
- bool test_result = true;
- /* Turns on PBIST clock in PBIST ACTivate register */
- writel(PBIST_PACT_PACT_MASK, base + PBIST_PACT);
- /* Set Margin mode register for Test mode */
- writel(PBIST_TEST_MODE, base + PBIST_MARGIN_MODE);
- /* Zero out Loop counter 0 */
- writel(0x0, base + PBIST_L0);
- /* Set algorithm bitmap */
- writel(config->algorithms_bit_map, base + PBIST_ALGO);
- /* Set Memory group bitmap */
- writel(config->memory_groups_bit_map, base + PBIST_RINFO);
- /* Zero out override register */
- writel(config->override, base + PBIST_OVER);
- /* Set Scramble value - 64 bit*/
- writel(config->scramble_value_lo, base + PBIST_SCR_LO);
- writel(config->scramble_value_hi, base + PBIST_SCR_HI);
- /* Set DLR register for ROM based testing and Config Access */
- writel(PBIST_DLR_DLR0_ROM_MASK
- | PBIST_DLR_DLR0_CAM_MASK, base + PBIST_DLR);
- udelay(1000);
- u32 timeout_count = 0;
Please move timeout_count at start of function
- while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) &&
(timeout_count++ < PBIST_MAX_TIMEOUT_VALUE))
;
Do you want to add some delay instead of just reading in a loop
- if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) {
test_result = false;
debug("%s(dev=%p): test failed\n", __func__, dev);
Fail is error , no ?
- } else {
debug("%s(dev=%p): test passed\n", __func__, dev);
- }
- writel(0xffffffff, VIM_STS(intr_num));
- return 0;
Caller always will see success
+}
+/**
- pbist_neg_self_test() - Run PBIST_negTEST on specified cores
- @config: pbist_config_neg structure for PBIST negative test
- Function to run PBIST failure insertion test
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_neg_self_test(struct pbist_config_neg *config) +{
- struct udevice *dev = k3_bist_priv->dev;
- void *base = k3_bist_priv->base;
- u32 intr_num = k3_bist_priv->intr_num;
- bool test_result = true;
- /* Turns on PBIST clock in PBIST ACTivate register */
- writel(PBIST_PACT_PACT_MASK, base + PBIST_PACT);
- /* Set Margin mode register for Test mode */
- writel(PBIST_FAILURE_INSERTION_TEST_MODE, base + PBIST_MARGIN_MODE);
- /* Zero out Loop counter 0 */
- writel(0x0, base + PBIST_L0);
- /* Set DLR register */
- writel(0x10, base + PBIST_DLR);
- /* Set Registers*/
- writel(0x00000001, base + PBIST_RF0L);
- writel(0x00003123, base + PBIST_RF0U);
- writel(0x0513FC02, base + PBIST_RF1L);
- writel(0x00000002, base + PBIST_RF1U);
- writel(0x00000003, base + PBIST_RF2L);
- writel(0x00000000, base + PBIST_RF2U);
- writel(0x00000004, base + PBIST_RF3L);
- writel(0x00000028, base + PBIST_RF3U);
- writel(0x64000044, base + PBIST_RF4L);
- writel(0x00000000, base + PBIST_RF4U);
- writel(0x0006A006, base + PBIST_RF5L);
- writel(0x00000000, base + PBIST_RF5U);
- writel(0x00000007, base + PBIST_RF6L);
- writel(0x0000A0A0, base + PBIST_RF6U);
- writel(0x00000008, base + PBIST_RF7L);
- writel(0x00000064, base + PBIST_RF7U);
- writel(0x00000009, base + PBIST_RF8L);
- writel(0x0000A5A5, base + PBIST_RF8U);
- writel(0x0000000A, base + PBIST_RF9L);
- writel(0x00000079, base + PBIST_RF9U);
- writel(0x00000000, base + PBIST_RF10L);
- writel(0x00000001, base + PBIST_RF10U);
- writel(0xAAAAAAAA, base + PBIST_D);
- writel(0xAAAAAAAA, base + PBIST_E);
too much direct values
- writel(config->CA2, base + PBIST_CA2);
- writel(config->CL0, base + PBIST_CL0);
- writel(config->CA3, base + PBIST_CA3);
- writel(config->I0, base + PBIST_I0);
- writel(config->CL1, base + PBIST_CL1);
- writel(config->I3, base + PBIST_I3);
- writel(config->I2, base + PBIST_I2);
- writel(config->CL2, base + PBIST_CL2);
- writel(config->CA1, base + PBIST_CA1);
- writel(config->CA0, base + PBIST_CA0);
- writel(config->CL3, base + PBIST_CL3);
- writel(config->I1, base + PBIST_I1);
- writel(config->RAMT, base + PBIST_RAMT);
- writel(config->CSR, base + PBIST_CSR);
- writel(config->CMS, base + PBIST_CMS);
- writel(0x00000009, base + PBIST_STR);
- /* Start PBIST */
- writel(0x00000001, base + PBIST_STR);
- udelay(1000);
- u32 timeout_count = 0;
- while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) &&
(timeout_count++ < PBIST_MAX_TIMEOUT_VALUE))
;
- if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) {
test_result = false;
debug("%s(dev=%p): test failed\n", __func__, dev);
- } else {
debug("%s(dev=%p): test passed\n", __func__, dev);
- }
- writel(0xffffffff, VIM_STS(intr_num));
- return 0;
Same as in above function for error
+}
+/**
- pbist_rom_self_test() - Run PBIST_ROM_TEST on specified cores
- @config: pbist_config_rom structure for PBIST negative test
- Function to run PBIST test of ROM
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_rom_self_test(struct pbist_config_rom *config) +{
- struct udevice *dev = k3_bist_priv->dev;
- void *base = k3_bist_priv->base;
- u32 intr_num = k3_bist_priv->intr_num;
- bool test_result = true;
- /* Turns on PBIST clock in PBIST ACTivate register */
- writel(0x1, base + PBIST_PACT);
- /* Set Margin mode register for Test mode */
- writel(0xf, base + PBIST_MARGIN_MODE);
- /* Zero out Loop counter 0 */
- writel(0x0, base + PBIST_L0);
- /* Set DLR register */
- writel(0x310, base + PBIST_DLR);
- /* Set Registers*/
- writel(0x00000001, base + PBIST_RF0L);
- writel(0x00003123, base + PBIST_RF0U);
- writel(0x7A400183, base + PBIST_RF1L);
- writel(0x00000060, base + PBIST_RF1U);
- writel(0x00000184, base + PBIST_RF2L);
- writel(0x00000000, base + PBIST_RF2U);
- writel(0x7B600181, base + PBIST_RF3L);
- writel(0x00000061, base + PBIST_RF3U);
- writel(0x00000000, base + PBIST_RF4L);
- writel(0x00000000, base + PBIST_RF4U);
- writel(config->D, base + PBIST_D);
- writel(config->E, base + PBIST_E);
- writel(config->CA2, base + PBIST_CA2);
- writel(config->CL0, base + PBIST_CL0);
- writel(config->CA3, base + PBIST_CA3);
- writel(config->I0, base + PBIST_I0);
- writel(config->CL1, base + PBIST_CL1);
- writel(config->I3, base + PBIST_I3);
- writel(config->I2, base + PBIST_I2);
- writel(config->CL2, base + PBIST_CL2);
- writel(config->CA1, base + PBIST_CA1);
- writel(config->CA0, base + PBIST_CA0);
- writel(config->CL3, base + PBIST_CL3);
- writel(config->I1, base + PBIST_I1);
- writel(config->RAMT, base + PBIST_RAMT);
- writel(config->CSR, base + PBIST_CSR);
- writel(config->CMS, base + PBIST_CMS);
- writel(0x00000009, base + PBIST_STR);
- /* Start PBIST */
- writel(0x00000001, base + PBIST_STR);
- udelay(1000);
Why delay is needed. please add comment for that
- u32 timeout_count = 0;
same as above
- while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) &&
(timeout_count++ < PBIST_MAX_TIMEOUT_VALUE))
;
- if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) {
test_result = false;
debug("%s(dev=%p): test failed\n", __func__, dev);
- } else {
debug("%s(dev=%p): test passed\n", __func__, dev);
- }
- writel(0xffffffff, VIM_STS(intr_num));
- return 0;
+}
+/**
- k3_bist_probe() - Basic probe
- @dev: corresponding BIST device
- Parses BIST info from device tree, and configures the module accordingly.
- Return: 0 if all goes good, else appropriate error message.
- */
+static int k3_bist_probe(struct udevice *dev) +{
- int ret = 0, num_runs, i, j;
- struct k3_bist_privdata *priv = dev_get_priv(dev);
- struct pbist_inst_info *info;
- debug("%s(dev=%p)\n", __func__, dev);
- priv = dev_get_priv(dev);
NULL error check for priv
- priv->dev = dev;
- k3_bist_priv = priv;
- priv->base = dev_remap_addr_index(dev, 0);
- if (!priv->base)
return -ENODEV;
- ret = dev_read_u32(dev, "ti,bist-instance", &priv->instance);
- if (!priv->instance)
return -ENODEV;
- switch (priv->instance) {
- case PBIST14_INSTANCE:
info = &pbist14_inst_info;
priv->intr_num = info->intr_num;
break;
- default:
dev_err(dev, "%s: PBIST instance %d not supported\n", __func__, priv->instance);
return -ENODEV;
- };
- /* Probe the cores under test */
- for (i = 0; ; i++) {
ret = core_get_by_index(dev, i, false);
if (ret)
break;
- }
- if (!i) {
dev_err(dev, "%s: Acquiring the core failed. ret = %d\n", __func__, ret);
return ret;
- }
Please add a check, what you expect in device tree at start of probe .
I assume, you can hit this only case of incorrect DT
- /* Check whether HW POST successfully completely PBIST on the MCU domain */
- ret = pbist_run_post_pbist_check();
- if (ret) {
dev_err(dev, "HW POST failed to run successfully %d\n", ret);
return ret;
- }
you might need to do this check first. before probing other cores
- /* Run PBIST test */
- num_runs = info->num_pbist_runs;
if you want num_runs configurable, prefer to use DT
- for (j = 0; j < num_runs; j++) {
ret = pbist_self_test(&info->pbist_config_run[j]);
if (ret) {
dev_err(dev, "failed to run PBIST test %d\n", ret);
return ret;
}
- }
Dummy question, will above run the BIST on all selected cores ?
- /* Run PBIST failure insertion test */
- ret = pbist_neg_self_test(&info->pbist_neg_config_run);
- if (ret) {
dev_err(dev, "failed to run PBIST negative test %d\n", ret);
return ret;
- }
- /* Run PBIST test on ROM */
- num_runs = info->num_pbist_rom_test_runs;
- for (j = 0; j < num_runs; j++) {
ret = pbist_rom_self_test(&info->pbist_rom_test_config_run[j]);
if (ret) {
dev_err(dev, "failed to run ROM PBIST test %d\n", ret);
return ret;
}
- }
- /* Power off cores under test */
- while (i--) {
ret = core_get_by_index(dev, i, true);
if (ret)
break;
- }
can we get rid from this 'i' , May you can do all core ON and OFF in one function,
Largely its from device tree
- if (i) {
dev_err(dev, "%s: Stopping the core failed. ret = %d\n", __func__, ret);
return ret;
- }
- return 0;
+}
+static const struct udevice_id k3_bist_ids[] = {
- { .compatible = "ti,j784s4-bist" },
- {}
+};
+U_BOOT_DRIVER(k3_bist) = {
- .name = "k3_bist",
- .of_match = k3_bist_ids,
- .id = UCLASS_MISC,
- .probe = k3_bist_probe,
- .priv_auto = sizeof(struct k3_bist_privdata),
+}; diff --git a/drivers/misc/k3_bist_static_data.h b/drivers/misc/k3_bist_static_data.h new file mode 100644 index 00000000000..f30fb7935b6 --- /dev/null +++ b/drivers/misc/k3_bist_static_data.h @@ -0,0 +1,551 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Static Data for Texas Instruments' BIST (Built-In Self-Test) driver
- Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
- */
+#ifndef __K3_BIST_STATIC_DATA_H +#define __K3_BIST_STATIC_DATA_H
+#define PBIST_MAX_NUM_RUNS 2 +#define NUM_MAX_PBIST_TEST_ROM_RUNS 13 +#define PBIST14_DFT_PBIST_CPU_0_INTR_NUM 311
+/* VIM Registers */ +#define VIM_STS_BASE 0x40f80404 +#define VIM_RAW_BASE 0x40f80400
+#define VIM_STS(i) (VIM_STS_BASE + (i) / 32 * 0x20) +#define VIM_RAW(i) (VIM_RAW_BASE + (i) / 32 * 0x20) +#define VIM_RAW_MASK(i) (BIT((i) % 32))
Above this SOC specific data , Please have some SOC specific data in another header file and include here.
So that adding next SOC will be easy
[..] +#if IS_ENABLED(CONFIG_SOC_K3_J784S4)
Please put this data in SOC specific header file
[..]

On 04/09/24 10:35, Kumar, Udit wrote:
On 9/3/2024 5:14 PM, Neha Malcom Francis wrote:
Add a driver for the BIST module which currently includes support for BIST IPs that trigger PBIST (Memory BIST).
Signed-off-by: Neha Malcom Francis n-francis@ti.com
drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/k3_bist.c | 507 ++++++++++++++++++++++++++ drivers/misc/k3_bist_static_data.h | 551 +++++++++++++++++++++++++++++ 4 files changed, 1067 insertions(+) create mode 100644 drivers/misc/k3_bist.c create mode 100644 drivers/misc/k3_bist_static_data.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6009d55f400..8e28a93d74c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -664,6 +664,14 @@ config ESM_K3 help Support ESM (Error Signaling Module) on TI K3 SoCs. +config K3_BIST + bool "Enable K3 BIST driver" + depends on ARCH_K3 + help + Support BIST (Built-In Self Test) module on TI K3 SoCs. This driver + supports running both PBIST (Memory BIST) and LBIST (Logic BIST) on + a region or IP in the SoC.
config MICROCHIP_FLEXCOM bool "Enable Microchip Flexcom driver" depends on MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e53d52c47b3..15c5c4810dd 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o obj-$(CONFIG_K3_AVS0) += k3_avs.o obj-$(CONFIG_ESM_K3) += k3_esm.o +obj-$(CONFIG_K3_BIST) += k3_bist.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o obj-$(CONFIG_SPL_SOCFPGA_DT_REG) += socfpga_dtreg.o diff --git a/drivers/misc/k3_bist.c b/drivers/misc/k3_bist.c new file mode 100644 index 00000000000..a4728376b73 --- /dev/null +++ b/drivers/misc/k3_bist.c @@ -0,0 +1,507 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Texas Instruments' BIST (Built-In Self-Test) driver
- Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
- * Neha Malcom Francis n-francis@ti.com
- */
+#include <dm.h> +#include <errno.h> +#include <clk.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <asm/arch/hardware.h> +#include <linux/soc/ti/ti_sci_protocol.h> +#include <remoteproc.h> +#include <power-domain.h>
In general, few macro's name are too long
many places hard-coded values are used, please consider to move to macro
driver looks to be j784s4 specific including header files ,
please see, if we can make this generic driver.
I've put SoC specific (J784S4 right now) data protected with SoC specific configs in k3_bist_static_data.h; the hardcoded values are a sequence for triggering a specific test, whatever is generic and known I have put as a macro, however I'll try to better understand the sequence if I can put them as macros.
+#include "k3_bist_static_data.h"
+/* PBIST Timeout Value */ +#define PBIST_MAX_TIMEOUT_VALUE 100000000
+/**
- struct k3_bist_privdata - K3 BIST structure
- @dev: device pointer
- @base: base of register set
- @instance: PBIST instance number
- @intr_num: corresponding interrupt ID of the PBIST instance
- */
+struct k3_bist_privdata { + struct udevice *dev; + void *base; + u32 instance; + u32 intr_num; +};
+static struct k3_bist_privdata *k3_bist_priv;
+/**
- pbist_run_post_pbist_check() - Check POST results
- Function to check whether HW Power-On Self Test, i.e. POST has run
- successfully on the MCU domain.
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_run_post_pbist_check(void)
Please consider to rename function name as per description above something like
check_pbist_results_of_mcu_domain,, if you agree
Also give more context, I believe, ROM runs BIST on MCU domain, Please consider to mention, if you want
Yes will do!
+{ + bool is_done, timed_out; + u32 mask; + u32 post_reg_val, shift;
+ /* Read HW POST status register */ + post_reg_val = readl(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT);
+ /* Check if HW POST PBIST was performed */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_DONE_SHIFT; + is_done = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
+ if (!is_done) { + /* HW POST: PBIST not completed, check if it timed out */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_TIMEOUT_SHIFT;
Too long macro name
+ timed_out = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
+ if (!timed_out) { + debug("%s: PBIST was not performed at all on this device for this core\n", + __func__); + return -EINVAL;
This is error no ? , move to dev_err instead of debug
The return in k3_bist_probe throws a dev_err saying HW POST failed to run successfully. So these were added as debugs in case the end user wants to know exact cause of failure, I can move it as a dev_err as well.
+ } else { + debug("%s: PBIST was attempted but timed out for this section\n", __func__); + return -ETIMEDOUT;
This is error no ? , move to dev_err instead of debug .
What next, reboot SOC or just continue booting in case of error
This is also something I wanted this RFC to address, I prefer rebooting SoC if HW POST fails. HW POST is performed by ROM based on certain switch settings, which implies that an end-user wants this check done if selected. And if it fails on the MCU domain itself, I do not think we should continue.
+ } + } else { + /* HW POST: PBIST was completed on this device, check the result */ + mask = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_FAIL_MASK;
+ if ((post_reg_val & mask) != 0) { + debug("%s: PBIST was completed, but the test failed\n", __func__); + return -EINVAL; + } else { + debug("%s: HW POST PBIST completed, test passed\n", __func__); + } + }
+ return 0; +}
+/**
- core_get_by_index() - Configure processor to correct state
Two operation here. please rename if possible
Will do, thanks!
- Function to configure processor under test to correct state for SW-initiated
- PBIST
- @dev: BIST device
- @index: corresponding index of the core in the cores-under-test list
- @turnoff: true if core is needed to be turned off
- Return: 0 if all went fine, else corresponding error.
- */
+int core_get_by_index(struct udevice *dev, int index, bool turnoff) +{ + struct ofnode_phandle_args args; + int ret; + struct udevice *dev_core;
+ ret = dev_read_phandle_with_args(dev, "cores-under-test", NULL, 0, index, &args); + if (ret) { + debug("%s: dev_read_phandle_with_args failed: %d\n", __func__, + ret); + return ret; + } + ret = uclass_get_device_by_ofnode(UCLASS_REMOTEPROC, args.node, &dev_core); + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed: %d\n", + __func__, ret); + return ret; + }
+ if (turnoff) { + struct power_domain pwrdmn; + struct clk fclk;
isn't some tisci call are ok to turn off the CPUs.
DM (Device Manager) firmware, responsible for power management is not up at this point in the boot flow (R5 SPL). Thus TISCI calls that turn on/turn off clocks and power domains are not available and we rely on the primitive clk-k3.c and ti-power-domain.c drivers to do this for us. As seen below, using the uclass functions which internally calls these primitive drivers would be the way to go.
I could have used the remoteproc framework to do this but currently the rproc driver uses TISCI firmware calls from DM and as mentioned above that's not possible.
We should probably target modifying our remoteproc driver to use these generic uclass APIs instead of direct TISCI calls.
+ ret = power_domain_get_by_index(dev_core, &pwrdmn, 0); + if (ret) { + dev_err(dev, "failed to get power domain for the core %d\n", ret); + return ret; + }
+ ret = clk_get_by_index(dev_core, 0, &fclk); + if (ret) { + dev_err(dev, "failed to get clock for the core %d\n", ret); + return ret; + }
+ ret = power_domain_off(&pwrdmn); + if (ret) { + dev_err(dev, "failed to power OFF the core %d\n", ret); + return ret; + }
+ ret = power_domain_free(&pwrdmn); + if (ret) { + dev_err(dev, "failed to free the core %d\n", ret); + return ret; + } + ret = clk_disable(&fclk); + if (ret) { + dev_err(dev, "failed to disable clock of the core %d\n", ret); + return ret; + } + } + return 0; +}
+/**
- pbist_self_test() - Run PBIST_TEST on specified cores
- @config: pbist_config structure for PBIST test
- Function to run PBIST_TEST
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_self_test(struct pbist_config *config) +{ + struct udevice *dev = k3_bist_priv->dev; + void *base = k3_bist_priv->base; + u32 intr_num = k3_bist_priv->intr_num; + bool test_result = true;
+ /* Turns on PBIST clock in PBIST ACTivate register */ + writel(PBIST_PACT_PACT_MASK, base + PBIST_PACT);
+ /* Set Margin mode register for Test mode */ + writel(PBIST_TEST_MODE, base + PBIST_MARGIN_MODE);
+ /* Zero out Loop counter 0 */ + writel(0x0, base + PBIST_L0);
+ /* Set algorithm bitmap */ + writel(config->algorithms_bit_map, base + PBIST_ALGO);
+ /* Set Memory group bitmap */ + writel(config->memory_groups_bit_map, base + PBIST_RINFO);
+ /* Zero out override register */ + writel(config->override, base + PBIST_OVER);
+ /* Set Scramble value - 64 bit*/ + writel(config->scramble_value_lo, base + PBIST_SCR_LO); + writel(config->scramble_value_hi, base + PBIST_SCR_HI);
+ /* Set DLR register for ROM based testing and Config Access */ + writel(PBIST_DLR_DLR0_ROM_MASK + | PBIST_DLR_DLR0_CAM_MASK, base + PBIST_DLR);
+ udelay(1000);
+ u32 timeout_count = 0;
Please move timeout_count at start of function
+ while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ;
Do you want to add some delay instead of just reading in a loop
That is possible... is there any benefit of delay over polling? Eithercase the possible time would be at max be PBIST_MAX_TIMEOUT_VALUE.
+ if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev);
Fail is error , no ?
+ } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + }
+ writel(0xffffffff, VIM_STS(intr_num));
+ return 0;
Caller always will see success
Right, I wasn't sure about what action to take based on the result.
+}
+/**
- pbist_neg_self_test() - Run PBIST_negTEST on specified cores
- @config: pbist_config_neg structure for PBIST negative test
- Function to run PBIST failure insertion test
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_neg_self_test(struct pbist_config_neg *config) +{ + struct udevice *dev = k3_bist_priv->dev; + void *base = k3_bist_priv->base; + u32 intr_num = k3_bist_priv->intr_num; + bool test_result = true;
+ /* Turns on PBIST clock in PBIST ACTivate register */ + writel(PBIST_PACT_PACT_MASK, base + PBIST_PACT);
+ /* Set Margin mode register for Test mode */ + writel(PBIST_FAILURE_INSERTION_TEST_MODE, base + PBIST_MARGIN_MODE);
+ /* Zero out Loop counter 0 */ + writel(0x0, base + PBIST_L0);
+ /* Set DLR register */ + writel(0x10, base + PBIST_DLR);
+ /* Set Registers*/ + writel(0x00000001, base + PBIST_RF0L); + writel(0x00003123, base + PBIST_RF0U); + writel(0x0513FC02, base + PBIST_RF1L); + writel(0x00000002, base + PBIST_RF1U); + writel(0x00000003, base + PBIST_RF2L); + writel(0x00000000, base + PBIST_RF2U); + writel(0x00000004, base + PBIST_RF3L); + writel(0x00000028, base + PBIST_RF3U); + writel(0x64000044, base + PBIST_RF4L); + writel(0x00000000, base + PBIST_RF4U); + writel(0x0006A006, base + PBIST_RF5L); + writel(0x00000000, base + PBIST_RF5U); + writel(0x00000007, base + PBIST_RF6L); + writel(0x0000A0A0, base + PBIST_RF6U); + writel(0x00000008, base + PBIST_RF7L); + writel(0x00000064, base + PBIST_RF7U); + writel(0x00000009, base + PBIST_RF8L); + writel(0x0000A5A5, base + PBIST_RF8U); + writel(0x0000000A, base + PBIST_RF9L); + writel(0x00000079, base + PBIST_RF9U); + writel(0x00000000, base + PBIST_RF10L); + writel(0x00000001, base + PBIST_RF10U); + writel(0xAAAAAAAA, base + PBIST_D); + writel(0xAAAAAAAA, base + PBIST_E);
too much direct values
Will try seeing if this sequence has a meaning I can move to MACROS for.
+ writel(config->CA2, base + PBIST_CA2); + writel(config->CL0, base + PBIST_CL0); + writel(config->CA3, base + PBIST_CA3); + writel(config->I0, base + PBIST_I0); + writel(config->CL1, base + PBIST_CL1); + writel(config->I3, base + PBIST_I3); + writel(config->I2, base + PBIST_I2); + writel(config->CL2, base + PBIST_CL2); + writel(config->CA1, base + PBIST_CA1); + writel(config->CA0, base + PBIST_CA0); + writel(config->CL3, base + PBIST_CL3); + writel(config->I1, base + PBIST_I1); + writel(config->RAMT, base + PBIST_RAMT); + writel(config->CSR, base + PBIST_CSR); + writel(config->CMS, base + PBIST_CMS);
+ writel(0x00000009, base + PBIST_STR);
+ /* Start PBIST */ + writel(0x00000001, base + PBIST_STR);
+ udelay(1000);
+ u32 timeout_count = 0;
+ while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ;
+ if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev); + } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + }
+ writel(0xffffffff, VIM_STS(intr_num));
+ return 0;
Same as in above function for error
+}
+/**
- pbist_rom_self_test() - Run PBIST_ROM_TEST on specified cores
- @config: pbist_config_rom structure for PBIST negative test
- Function to run PBIST test of ROM
- Return: 0 if all went fine, else corresponding error.
- */
+int pbist_rom_self_test(struct pbist_config_rom *config) +{ + struct udevice *dev = k3_bist_priv->dev; + void *base = k3_bist_priv->base; + u32 intr_num = k3_bist_priv->intr_num; + bool test_result = true;
+ /* Turns on PBIST clock in PBIST ACTivate register */ + writel(0x1, base + PBIST_PACT);
+ /* Set Margin mode register for Test mode */ + writel(0xf, base + PBIST_MARGIN_MODE);
+ /* Zero out Loop counter 0 */ + writel(0x0, base + PBIST_L0);
+ /* Set DLR register */ + writel(0x310, base + PBIST_DLR);
+ /* Set Registers*/ + writel(0x00000001, base + PBIST_RF0L); + writel(0x00003123, base + PBIST_RF0U); + writel(0x7A400183, base + PBIST_RF1L); + writel(0x00000060, base + PBIST_RF1U); + writel(0x00000184, base + PBIST_RF2L); + writel(0x00000000, base + PBIST_RF2U); + writel(0x7B600181, base + PBIST_RF3L); + writel(0x00000061, base + PBIST_RF3U); + writel(0x00000000, base + PBIST_RF4L); + writel(0x00000000, base + PBIST_RF4U);
+ writel(config->D, base + PBIST_D); + writel(config->E, base + PBIST_E); + writel(config->CA2, base + PBIST_CA2); + writel(config->CL0, base + PBIST_CL0); + writel(config->CA3, base + PBIST_CA3); + writel(config->I0, base + PBIST_I0); + writel(config->CL1, base + PBIST_CL1); + writel(config->I3, base + PBIST_I3); + writel(config->I2, base + PBIST_I2); + writel(config->CL2, base + PBIST_CL2); + writel(config->CA1, base + PBIST_CA1); + writel(config->CA0, base + PBIST_CA0); + writel(config->CL3, base + PBIST_CL3); + writel(config->I1, base + PBIST_I1); + writel(config->RAMT, base + PBIST_RAMT); + writel(config->CSR, base + PBIST_CSR); + writel(config->CMS, base + PBIST_CMS);
+ writel(0x00000009, base + PBIST_STR);
+ /* Start PBIST */ + writel(0x00000001, base + PBIST_STR);
+ udelay(1000);
Why delay is needed. please add comment for that
+ u32 timeout_count = 0;
same as above
+ while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ;
+ if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev); + } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + }
+ writel(0xffffffff, VIM_STS(intr_num));
+ return 0; +}
+/**
- k3_bist_probe() - Basic probe
- @dev: corresponding BIST device
- Parses BIST info from device tree, and configures the module accordingly.
- Return: 0 if all goes good, else appropriate error message.
- */
+static int k3_bist_probe(struct udevice *dev) +{ + int ret = 0, num_runs, i, j; + struct k3_bist_privdata *priv = dev_get_priv(dev); + struct pbist_inst_info *info;
+ debug("%s(dev=%p)\n", __func__, dev);
+ priv = dev_get_priv(dev);
NULL error check for priv
Got it, thanks!
+ priv->dev = dev;
+ k3_bist_priv = priv;
+ priv->base = dev_remap_addr_index(dev, 0); + if (!priv->base) + return -ENODEV;
+ ret = dev_read_u32(dev, "ti,bist-instance", &priv->instance); + if (!priv->instance) + return -ENODEV;
+ switch (priv->instance) { + case PBIST14_INSTANCE: + info = &pbist14_inst_info; + priv->intr_num = info->intr_num; + break; + default: + dev_err(dev, "%s: PBIST instance %d not supported\n", __func__, priv->instance); + return -ENODEV; + };
+ /* Probe the cores under test */ + for (i = 0; ; i++) { + ret = core_get_by_index(dev, i, false); + if (ret) + break; + }
+ if (!i) { + dev_err(dev, "%s: Acquiring the core failed. ret = %d\n", __func__, ret); + return ret; + }
Please add a check, what you expect in device tree at start of probe .
I assume, you can hit this only case of incorrect DT
Right, will add a check at the start.
+ /* Check whether HW POST successfully completely PBIST on the MCU domain */ + ret = pbist_run_post_pbist_check(); + if (ret) { + dev_err(dev, "HW POST failed to run successfully %d\n", ret); + return ret; + }
you might need to do this check first. before probing other cores
Hm yes okay, can move that in front.
+ /* Run PBIST test */ + num_runs = info->num_pbist_runs;
if you want num_runs configurable, prefer to use DT
+ for (j = 0; j < num_runs; j++) { + ret = pbist_self_test(&info->pbist_config_run[j]); + if (ret) { + dev_err(dev, "failed to run PBIST test %d\n", ret); + return ret; + } + }
Dummy question, will above run the BIST on all selected cores ?
A probe of a single BIST instance will run the BIST test on all it's modules/cores. So yes, each test is triggering the BIST run on all cores.
+ /* Run PBIST failure insertion test */ + ret = pbist_neg_self_test(&info->pbist_neg_config_run); + if (ret) { + dev_err(dev, "failed to run PBIST negative test %d\n", ret); + return ret; + }
+ /* Run PBIST test on ROM */ + num_runs = info->num_pbist_rom_test_runs;
+ for (j = 0; j < num_runs; j++) { + ret = pbist_rom_self_test(&info->pbist_rom_test_config_run[j]); + if (ret) { + dev_err(dev, "failed to run ROM PBIST test %d\n", ret); + return ret; + } + }
+ /* Power off cores under test */ + while (i--) { + ret = core_get_by_index(dev, i, true); + if (ret) + break; + }
can we get rid from this 'i' , May you can do all core ON and OFF in one function,
Largely its from device tree
Okay I will try changing this.
+ if (i) { + dev_err(dev, "%s: Stopping the core failed. ret = %d\n", __func__, ret); + return ret; + }
+ return 0; +}
+static const struct udevice_id k3_bist_ids[] = { + { .compatible = "ti,j784s4-bist" }, + {} +};
+U_BOOT_DRIVER(k3_bist) = { + .name = "k3_bist", + .of_match = k3_bist_ids, + .id = UCLASS_MISC, + .probe = k3_bist_probe, + .priv_auto = sizeof(struct k3_bist_privdata), +}; diff --git a/drivers/misc/k3_bist_static_data.h b/drivers/misc/k3_bist_static_data.h new file mode 100644 index 00000000000..f30fb7935b6 --- /dev/null +++ b/drivers/misc/k3_bist_static_data.h @@ -0,0 +1,551 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Static Data for Texas Instruments' BIST (Built-In Self-Test) driver
- Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
- */
+#ifndef __K3_BIST_STATIC_DATA_H +#define __K3_BIST_STATIC_DATA_H
+#define PBIST_MAX_NUM_RUNS 2 +#define NUM_MAX_PBIST_TEST_ROM_RUNS 13 +#define PBIST14_DFT_PBIST_CPU_0_INTR_NUM 311
+/* VIM Registers */ +#define VIM_STS_BASE 0x40f80404 +#define VIM_RAW_BASE 0x40f80400
+#define VIM_STS(i) (VIM_STS_BASE + (i) / 32 * 0x20) +#define VIM_RAW(i) (VIM_RAW_BASE + (i) / 32 * 0x20) +#define VIM_RAW_MASK(i) (BIT((i) % 32))
Above this SOC specific data , Please have some SOC specific data in another header file and include here.
So that adding next SOC will be easy
[..] +#if IS_ENABLED(CONFIG_SOC_K3_J784S4)
Please put this data in SOC specific header file
Okay I will create an SoC specific header file.
[..]
Thanks for reviewing!

On 9/5/2024 3:11 PM, Neha Malcom Francis wrote:
On 04/09/24 10:35, Kumar, Udit wrote:
On 9/3/2024 5:14 PM, Neha Malcom Francis wrote:
Add a driver for the BIST module which currently includes support for BIST IPs that trigger PBIST (Memory BIST).
Signed-off-by: Neha Malcom Francis n-francis@ti.com
drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/k3_bist.c | 507 ++++++++++++++++++++++++++ drivers/misc/k3_bist_static_data.h | 551 +++++++++++++++++++++++++++++ 4 files changed, 1067 insertions(+) create mode 100644 drivers/misc/k3_bist.c create mode 100644 drivers/misc/k3_bist_static_data.h
[...]
In general, few macro's name are too long
many places hard-coded values are used, please consider to move to macro
driver looks to be j784s4 specific including header files ,
please see, if we can make this generic driver.
I've put SoC specific (J784S4 right now) data protected with SoC specific configs in k3_bist_static_data.h; the hardcoded values are a sequence for triggering a specific test, whatever is generic and known I have put as a macro, however I'll try to better understand the sequence if I can put them as macros.
+#include "k3_bist_static_data.h"
[...]
Please consider to rename function name as per description above something like
check_pbist_results_of_mcu_domain,, if you agree
Also give more context, I believe, ROM runs BIST on MCU domain, Please consider to mention, if you want
Yes will do!
+{ + bool is_done, timed_out; + u32 mask; + u32 post_reg_val, shift;
+ /* Read HW POST status register */ + post_reg_val = readl(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT);
+ /* Check if HW POST PBIST was performed */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_DONE_SHIFT; + is_done = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
+ if (!is_done) { + /* HW POST: PBIST not completed, check if it timed out */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_TIMEOUT_SHIFT;
Too long macro name
+ timed_out = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
+ if (!timed_out) { + debug("%s: PBIST was not performed at all on this device for this core\n", + __func__); + return -EINVAL;
This is error no ? , move to dev_err instead of debug
The return in k3_bist_probe throws a dev_err saying HW POST failed to run successfully. So these were added as debugs in case the end user wants to know exact cause of failure, I can move it as a dev_err as well.
ok, thanks
+ } else { + debug("%s: PBIST was attempted but timed out for this section\n", __func__); + return -ETIMEDOUT;
This is error no ? , move to dev_err instead of debug .
What next, reboot SOC or just continue booting in case of error
This is also something I wanted this RFC to address, I prefer rebooting SoC if HW POST fails. HW POST is performed by ROM based on certain switch settings, which implies that an end-user wants this check done if selected. And if it fails on the MCU domain itself, I do not think we should continue.
Ok, if you are saying BIST in MCU domain in done based upon some switch settings, then please put that switch logic here .
Reading code above looks, BIST run always
if (!is_done) { + /* HW POST: PBIST not completed, check if it timed out */ + } else { + /* HW POST: PBIST was completed on this device, check the result */
So now have three conditions, 1) BIST not attempted 2) BIST ran and passed 3) BIST ran and failed
For 1) condition, please see if you can read some register or switch settings or so.
For 3) , as default we should hang.. In case users wants to continue on failure they can modify u-boot source to do so :)
[..] isn't some tisci call are ok to turn off the CPUs.
DM (Device Manager) firmware, responsible for power management is not up at this point in the boot flow (R5 SPL). Thus TISCI calls that turn on/turn off clocks and power domains are not available and we rely on the primitive clk-k3.c and ti-power-domain.c drivers to do this for us. As seen below, using the uclass functions which internally calls these primitive drivers would be the way to go.
But DM is kind implemented by dev-data and dev-clk logic ?
For few calls DM just talk to TIFS, which are available at this point.
I request to check once, if possible
I could have used the remoteproc framework to do this but currently the rproc driver uses TISCI firmware calls from DM and as mentioned above that's not possible.
We should probably target modifying our remoteproc driver to use these generic uclass APIs instead of direct TISCI calls.
Ok,
[...] + udelay(1000);
+ u32 timeout_count = 0;
Please move timeout_count at start of function
+ while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ;
Do you want to add some delay instead of just reading in a loop
That is possible... is there any benefit of delay over polling? Eithercase the possible time would be at max be PBIST_MAX_TIMEOUT_VALUE.
You could be definitive in waiting for this register,
Say if hardware specs says, VIM register will be set in max time of 100 ms. then
keep PBIST_MAX_TIMEOUT_VALUE as 100 and read wait for 1 ms and then read.
+ if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev);
Fail is error , no ?
+ } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + }
+ writel(0xffffffff, VIM_STS(intr_num));
+ return 0;
Caller always will see success
Right, I wasn't sure about what action to take based on the result.
Failure is failure, as default please print and call hang
+}
+/** [..]

Hi Udit,
On 05/09/24 17:20, Kumar, Udit wrote:
On 9/5/2024 3:11 PM, Neha Malcom Francis wrote:
On 04/09/24 10:35, Kumar, Udit wrote:
On 9/3/2024 5:14 PM, Neha Malcom Francis wrote:
Add a driver for the BIST module which currently includes support for BIST IPs that trigger PBIST (Memory BIST).
Signed-off-by: Neha Malcom Francis n-francis@ti.com
drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/k3_bist.c | 507 ++++++++++++++++++++++++++ drivers/misc/k3_bist_static_data.h | 551 +++++++++++++++++++++++++++++ 4 files changed, 1067 insertions(+) create mode 100644 drivers/misc/k3_bist.c create mode 100644 drivers/misc/k3_bist_static_data.h
[...]
In general, few macro's name are too long
many places hard-coded values are used, please consider to move to macro
driver looks to be j784s4 specific including header files ,
please see, if we can make this generic driver.
I've put SoC specific (J784S4 right now) data protected with SoC specific configs in k3_bist_static_data.h; the hardcoded values are a sequence for triggering a specific test, whatever is generic and known I have put as a macro, however I'll try to better understand the sequence if I can put them as macros.
+#include "k3_bist_static_data.h"
[...]
Please consider to rename function name as per description above something like
check_pbist_results_of_mcu_domain,, if you agree
Also give more context, I believe, ROM runs BIST on MCU domain, Please consider to mention, if you want
Yes will do!
+{ + bool is_done, timed_out; + u32 mask; + u32 post_reg_val, shift;
+ /* Read HW POST status register */ + post_reg_val = readl(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT);
+ /* Check if HW POST PBIST was performed */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_DONE_SHIFT; + is_done = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
+ if (!is_done) { + /* HW POST: PBIST not completed, check if it timed out */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_PBIST_TIMEOUT_SHIFT;
Too long macro name
+ timed_out = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false;
+ if (!timed_out) { + debug("%s: PBIST was not performed at all on this device for this core\n", + __func__); + return -EINVAL;
This is error no ? , move to dev_err instead of debug
The return in k3_bist_probe throws a dev_err saying HW POST failed to run successfully. So these were added as debugs in case the end user wants to know exact cause of failure, I can move it as a dev_err as well.
ok, thanks
+ } else { + debug("%s: PBIST was attempted but timed out for this section\n", __func__); + return -ETIMEDOUT;
This is error no ? , move to dev_err instead of debug .
What next, reboot SOC or just continue booting in case of error
This is also something I wanted this RFC to address, I prefer rebooting SoC if HW POST fails. HW POST is performed by ROM based on certain switch settings, which implies that an end-user wants this check done if selected. And if it fails on the MCU domain itself, I do not think we should continue.
Ok, if you are saying BIST in MCU domain in done based upon some switch settings, then please put that switch logic here .
Reading code above looks, BIST run always
if (!is_done) { + /* HW POST: PBIST not completed, check if it timed out */ + } else { + /* HW POST: PBIST was completed on this device, check the result */
So now have three conditions,
- BIST not attempted
- BIST ran and passed
- BIST ran and failed
For 1) condition, please see if you can read some register or switch settings or so.
For 3) , as default we should hang.. In case users wants to continue on failure they can modify u-boot source to do so :)
Okay that makes sense, I will make the change in v1.
[..] isn't some tisci call are ok to turn off the CPUs.
DM (Device Manager) firmware, responsible for power management is not up at this point in the boot flow (R5 SPL). Thus TISCI calls that turn on/turn off clocks and power domains are not available and we rely on the primitive clk-k3.c and ti-power-domain.c drivers to do this for us. As seen below, using the uclass functions which internally calls these primitive drivers would be the way to go.
But DM is kind implemented by dev-data and dev-clk logic ?
Yes, it is. I am using the uclass API for both power and clock which internally uses the drivers with this logic.
For few calls DM just talk to TIFS, which are available at this point.
Yes, but from my POV this driver does not need to know what the clock and power APIs internally do, it should just call the uclass APIs like this. And in case of power off, whatever DM would have done is already covered in ti-power-domain.c
I request to check once, if possible
I could have used the remoteproc framework to do this but currently the rproc driver uses TISCI firmware calls from DM and as mentioned above that's not possible.
We should probably target modifying our remoteproc driver to use these generic uclass APIs instead of direct TISCI calls.
Ok,
[...] + udelay(1000);
+ u32 timeout_count = 0;
Please move timeout_count at start of function
+ while ((!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) + ;
Do you want to add some delay instead of just reading in a loop
That is possible... is there any benefit of delay over polling? Eithercase the possible time would be at max be PBIST_MAX_TIMEOUT_VALUE.
You could be definitive in waiting for this register,
Say if hardware specs says, VIM register will be set in max time of 100 ms. then
keep PBIST_MAX_TIMEOUT_VALUE as 100 and read wait for 1 ms and then read.
I'm not sure I understand, the timeout condition if it happens first it will break from the loop, so the polling will not continue indefinitely.
+ if (!(readl(VIM_RAW(intr_num)) & VIM_RAW_MASK(intr_num))) { + test_result = false; + debug("%s(dev=%p): test failed\n", __func__, dev);
Fail is error , no ?
+ } else { + debug("%s(dev=%p): test passed\n", __func__, dev); + }
+ writel(0xffffffff, VIM_STS(intr_num));
+ return 0;
Caller always will see success
Right, I wasn't sure about what action to take based on the result.
Failure is failure, as default please print and call hang
Got it!
+}
+/** [..]

Trigger BIST on MAIN_R5_2_x cores from R5 SPL on J784S4.
Signed-off-by: Neha Malcom Francis n-francis@ti.com --- arch/arm/mach-k3/j784s4/j784s4_init.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/arch/arm/mach-k3/j784s4/j784s4_init.c b/arch/arm/mach-k3/j784s4/j784s4_init.c index 07b5d7d7504..993d24a9447 100644 --- a/arch/arm/mach-k3/j784s4/j784s4_init.c +++ b/arch/arm/mach-k3/j784s4/j784s4_init.c @@ -233,9 +233,20 @@ void k3_mem_init(void)
void board_init_f(ulong dummy) { + struct udevice *dev; + int ret; + k3_spl_init(); k3_mem_init();
+ if (IS_ENABLED(CONFIG_CPU_V7R) && IS_ENABLED(CONFIG_K3_BIST)) { + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_DRIVER_GET(k3_bist), + &dev); + if (ret) + printf("Failed to run BIST: %d\n", ret); + } + if (IS_ENABLED(CONFIG_CPU_V7R)) setup_navss_nb();

Enable both the BIST driver and the R5 remoteproc to be able to successfully probe and trigger BIST tests on MAIN_R5 cores.
Signed-off-by: Neha Malcom Francis n-francis@ti.com --- configs/j784s4_evm_r5_defconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/configs/j784s4_evm_r5_defconfig b/configs/j784s4_evm_r5_defconfig index a1168819497..450abb35916 100644 --- a/configs/j784s4_evm_r5_defconfig +++ b/configs/j784s4_evm_r5_defconfig @@ -126,6 +126,7 @@ CONFIG_POWER_DOMAIN=y CONFIG_TI_POWER_DOMAIN=y CONFIG_K3_SYSTEM_CONTROLLER=y CONFIG_REMOTEPROC_TI_K3_ARM64=y +CONFIG_REMOTEPROC_TI_K3_R5F=y CONFIG_RESET_TI_SCI=y CONFIG_DM_SERIAL=y CONFIG_SOC_DEVICE=y @@ -146,3 +147,4 @@ CONFIG_FS_FAT_MAX_CLUSTSIZE=16384 CONFIG_PANIC_HANG=y CONFIG_LIB_RATIONAL=y CONFIG_SPL_LIB_RATIONAL=y +CONFIG_K3_BIST=y
participants (2)
-
Kumar, Udit
-
Neha Malcom Francis