diff options
Diffstat (limited to 'drivers/misc/k3_bist.c')
-rw-r--r-- | drivers/misc/k3_bist.c | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/drivers/misc/k3_bist.c b/drivers/misc/k3_bist.c new file mode 100644 index 00000000000..3acb1a1ac1f --- /dev/null +++ b/drivers/misc/k3_bist.c @@ -0,0 +1,807 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Texas Instruments' BIST (Built-In Self-Test) driver + * + * Copyright (C) 2025 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.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 + * @pbist_base: base of register set for PBIST + * @instance: PBIST instance number + * @intr_num: corresponding interrupt ID of the PBIST instance + * @lbist_ctrl_mmr: base of CTRL MMR register set for LBIST + */ +struct k3_bist_privdata { + struct udevice *dev; + void *pbist_base; + u32 instance; + u32 intr_num; + void *lbist_ctrl_mmr; + struct pbist_inst_info *pbist_info; + struct lbist_inst_info *lbist_info; +}; + +static struct k3_bist_privdata *k3_bist_priv; + +/** + * check_post_pbist_result() - 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. + */ +static int check_post_pbist_result(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) { + printf("%s: PBIST was not performed at all on this device for this core\n", + __func__); + return -EINVAL; + } + printf("%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) { + printf("%s: PBIST was completed, but the test failed\n", __func__); + return -EINVAL; + } + debug("%s: HW POST PBIST completed, test passed\n", __func__); + } + + return 0; +} + +/** + * check_post_lbist_result() - 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. + */ +static int check_post_lbist_result(void) +{ + bool is_done, timed_out; + u32 post_reg_val, shift; + u32 calculated_misr, expected_misr; + + /* Read HW POST status register */ + post_reg_val = readl(WKUP_CTRL_MMR0_BASE + WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT); + + /* Check if HW POST LBIST was performed */ + shift = WKUP_CTRL_MMR_CFG0_WKUP_POST_STAT_POST_MCU_LBIST_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_LBIST_TIMEOUT_SHIFT; + timed_out = (((post_reg_val >> shift) & 0x1u) == 0x1u) ? (bool)true : (bool)false; + + if (!timed_out) { + printf("%s: PBIST was not performed at all on this device for this core\n", + __func__); + return -EINVAL; + } + printf("%s: PBIST was attempted but timed out for this section\n", + __func__); + return -ETIMEDOUT; + + } else { + /* Get the output MISR and the expected MISR which 0 for MCU domain */ + lbist_get_misr((void *)MCU_LBIST_BASE, &calculated_misr); + expected_misr = readl(MCU_CTRL_MMR0_CFG0_BASE + MCU_CTRL_MMR_CFG0_MCU_LBIST_SIG); + + if (calculated_misr != expected_misr) { + /* HW POST: LBIST was completed, but the test failed for this core */ + printf("%s: calculated MISR != expected MISR\n", __func__); + debug("%s: calculated MISR = %x\n", __func__, calculated_misr); + debug("%s: expected MISR = %x\n", __func__, expected_misr); + return -EINVAL; + } + debug("%s: HW POST LBIST completed, test passed\n", __func__); + } + + 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. + */ +static int pbist_self_test(struct pbist_config *config) +{ + void *base = k3_bist_priv->pbist_base; + + /* 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); + + /* Allow time for completion of test*/ + udelay(1000); + + if (readl(base + PBIST_FSRF)) { + printf("%s: test failed\n", __func__); + return -EINVAL; + } + + 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. + */ +static int pbist_neg_self_test(struct pbist_config_neg *config) +{ + void *base = k3_bist_priv->pbist_base; + + /* 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); + + /* Allow time for completion of test*/ + udelay(1000); + + if (readl(base + PBIST_FSRF) == 0) { + printf("%s: test failed\n", __func__); + return -EINVAL; + } + + 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. + */ +static int pbist_rom_self_test(struct pbist_config_rom *config) +{ + void *base = k3_bist_priv->pbist_base; + + /* 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); + + /* Allow time for completion of test*/ + udelay(1000); + + if (readl(base + PBIST_FSRF)) { + printf("%s: test failed\n", __func__); + return -EINVAL; + } + + return 0; +} + +/** + * lbist_program_config() - Program LBIST config + * @config: lbist_config structure for LBIST test + */ +static void lbist_program_config(struct lbist_config *config) +{ + void *base = k3_bist_priv->lbist_ctrl_mmr; + + lbist_set_clock_delay(base, config->dc_def); + lbist_set_divide_ratio(base, config->divide_ratio); + lbist_clear_load_div(base); + lbist_set_load_div(base); + lbist_set_num_stuck_at_patterns(base, config->static_pc_def); + lbist_set_num_set_patterns(base, config->set_pc_def); + lbist_set_num_reset_patterns(base, config->reset_pc_def); + lbist_set_num_chain_test_patterns(base, config->scan_pc_def); + lbist_set_seed(base, config->prpg_def_l, config->prpg_def_u); +} + +/** + * lbist_enable_isolation() - LBIST Enable Isolation + * @config: lbist_config structure for LBIST test + */ +void lbist_enable_isolation(void) +{ + void *base = k3_bist_priv->lbist_ctrl_mmr; + u32 reg_val; + + reg_val = readl(base + LBIST_SPARE0); + writel(reg_val | (LBIST_SPARE0_LBIST_SELFTEST_EN_MASK), base + LBIST_SPARE0); +} + +/** + * lbist_disable_isolation() - LBIST Disable Isolation + * @config: lbist_config structure for LBIST test + */ +void lbist_disable_isolation(void) +{ + void *base = k3_bist_priv->lbist_ctrl_mmr; + u32 reg_val; + + reg_val = readl(base + LBIST_SPARE0); + writel(reg_val & (~(LBIST_SPARE0_LBIST_SELFTEST_EN_MASK)), base + LBIST_SPARE0); +} + +/** + * lbist_enable_run_bist_mode() - LBIST Enable run BIST mode + * @config: lbist_config structure for LBIST test + */ +static void lbist_enable_run_bist_mode(struct lbist_config *config) +{ + void *base = k3_bist_priv->lbist_ctrl_mmr; + u32 reg_val; + + reg_val = readl(base + LBIST_CTRL); + writel(reg_val | (LBIST_CTRL_RUNBIST_MODE_MAX << LBIST_CTRL_RUNBIST_MODE_SHIFT), + base + LBIST_CTRL); +} + +/** + * lbist_start() - Start LBIST test + * @config: lbist_config structure for LBIST test + */ +static void lbist_start(struct lbist_config *config) +{ + struct udevice *dev = k3_bist_priv->dev; + void *base = k3_bist_priv->lbist_ctrl_mmr; + u32 reg_val; + u32 timeout_count = 0; + + reg_val = readl(base + LBIST_CTRL); + writel(reg_val | (LBIST_CTRL_BIST_RESET_MAX << LBIST_CTRL_BIST_RESET_SHIFT), + base + LBIST_CTRL); + + reg_val = readl(base + LBIST_CTRL); + writel(reg_val | (LBIST_CTRL_BIST_RUN_MAX << LBIST_CTRL_BIST_RUN_SHIFT), + base + LBIST_CTRL); + + reg_val = readl(base + LBIST_STAT); + if ((reg_val & LBIST_STAT_BIST_RUNNING_MASK) != 0) + debug("%s(dev=%p): LBIST is running\n", __func__, dev); + + while (((!(readl(base + LBIST_STAT) & LBIST_STAT_BIST_DONE_MASK))) && + (timeout_count++ < PBIST_MAX_TIMEOUT_VALUE)) { + } + + if (!(readl(base + LBIST_STAT) & LBIST_STAT_BIST_DONE_MASK)) + printf("%s(dev=%p): test failed\n", __func__, dev); +} + +/** + * lbist_check_result() - Check LBIST test result + * @config: lbist_config structure for LBIST test + * + * Return: 0 if all went fine, else corresponding error. + */ +static int lbist_check_result(struct lbist_config *config) +{ + void *base = k3_bist_priv->lbist_ctrl_mmr; + struct lbist_inst_info *info = k3_bist_priv->lbist_info; + u32 calculated_misr; + u32 expected_misr; + + lbist_get_misr(base, &calculated_misr); + expected_misr = info->expected_misr; + lbist_clear_run_bist_mode(base); + lbist_stop(base); + lbist_reset(base); + + if (calculated_misr != expected_misr) { + printf("calculated_misr != expected_misr\n %x %x\n", + calculated_misr, expected_misr); + return -EINVAL; + } + + return 0; +} + +static int k3_run_lbist(void) +{ + /* Check whether HW POST successfully completely LBIST on the MCU domain */ + struct lbist_inst_info *info_lbist = k3_bist_priv->lbist_info; + + lbist_program_config(&info_lbist->lbist_conf); + lbist_enable_isolation(); + lbist_reset(&info_lbist->lbist_conf); + lbist_enable_run_bist_mode(&info_lbist->lbist_conf); + lbist_start(&info_lbist->lbist_conf); + if (lbist_check_result(&info_lbist->lbist_conf)) { + printf("%s: test failed\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int k3_run_lbist_post(void) +{ + if (check_post_lbist_result()) { + printf("HW POST LBIST failed to run successfully\n"); + return -EINVAL; + } + + return 0; +} + +static int k3_run_pbist_post(void) +{ + /* Check whether HW POST successfully completely PBIST on the MCU domain */ + if (check_post_pbist_result()) { + printf("HW POST failed to run successfully\n"); + return -EINVAL; + } + + return 0; +} + +static int k3_run_pbist(void) +{ + /* Run PBIST test */ + struct pbist_inst_info *info = k3_bist_priv->pbist_info; + int num_runs = info->num_pbist_runs; + + for (int j = 0; j < num_runs; j++) { + if (pbist_self_test(&info->pbist_config_run[j])) { + printf("failed to run PBIST test\n"); + return -EINVAL; + } + } + + return 0; +} + +static int k3_run_pbist_neg(void) +{ + /* Run PBIST failure insertion test */ + struct pbist_inst_info *info = k3_bist_priv->pbist_info; + + if (pbist_neg_self_test(&info->pbist_neg_config_run)) { + printf("failed to run PBIST negative test\n"); + return -EINVAL; + } + + return 0; +} + +static int k3_run_pbist_rom(void) +{ + /* Run PBIST test on ROM */ + struct pbist_inst_info *info = k3_bist_priv->pbist_info; + int num_runs = info->num_pbist_rom_test_runs; + + for (int j = 0; j < num_runs; j++) { + if (pbist_rom_self_test(&info->pbist_rom_test_config_run[j])) { + printf("failed to run ROM PBIST test\n"); + return -EINVAL; + } + } + + return 0; +} + +int prepare_pbist(struct ti_sci_handle *handle) +{ + struct ti_sci_proc_ops *proc_ops = &handle->ops.proc_ops; + struct ti_sci_dev_ops *dev_ops = &handle->ops.dev_ops; + struct pbist_inst_info *info_pbist = k3_bist_priv->pbist_info; + struct core_under_test *cut = info_pbist->cut; + + if (proc_ops->proc_request(handle, cut[0].proc_id)) { + printf("%s: requesting primary core failed\n", __func__); + return -EINVAL; + } + + if (proc_ops->proc_request(handle, cut[1].proc_id)) { + printf("%s: requesting secondary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->set_device_resets(handle, cut[0].dev_id, 0x1)) { + printf("%s: local reset primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->set_device_resets(handle, cut[1].dev_id, 0x1)) { + printf("%s: local reset secondary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->get_device(handle, cut[0].dev_id)) { + printf("%s: power on primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->get_device(handle, cut[1].dev_id)) { + printf("%s: power on secondary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->get_device(handle, info_pbist->dev_id)) { + printf("%s: power on PBIST failed\n", __func__); + return -EINVAL; + } + + return 0; +} + +int deprepare_pbist(struct ti_sci_handle *handle) +{ + struct ti_sci_proc_ops *proc_ops = &handle->ops.proc_ops; + struct ti_sci_dev_ops *dev_ops = &handle->ops.dev_ops; + struct pbist_inst_info *info_pbist = k3_bist_priv->pbist_info; + struct core_under_test *cut = info_pbist->cut; + + if (dev_ops->put_device(handle, info_pbist->dev_id)) { + printf("%s: power off PBIST failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->put_device(handle, cut[1].dev_id)) { + printf("%s: power off secondary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->put_device(handle, cut[0].dev_id)) { + printf("%s: power off primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->set_device_resets(handle, cut[0].dev_id, 0)) { + printf("%s: putting primary core out of local reset failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->set_device_resets(handle, cut[1].dev_id, 0)) { + printf("%s: putting secondary core out of local reset failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->put_device(handle, cut[0].dev_id)) { + printf("%s: power off primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->put_device(handle, cut[1].dev_id)) { + printf("%s: power off secondary core failed\n", __func__); + return -EINVAL; + } + + if (proc_ops->proc_release(handle, cut[0].proc_id)) { + printf("%s: release primary core failed\n", __func__); + return -EINVAL; + } + + if (proc_ops->proc_release(handle, cut[1].proc_id)) { + printf("%s: release secondary core failed\n", __func__); + return -EINVAL; + } + + return 0; +} + +int prepare_lbist(struct ti_sci_handle *handle) +{ + struct ti_sci_proc_ops *proc_ops = &handle->ops.proc_ops; + struct ti_sci_dev_ops *dev_ops = &handle->ops.dev_ops; + struct lbist_inst_info *info_lbist = k3_bist_priv->lbist_info; + struct core_under_test *cut = &info_lbist->cut; + + if (proc_ops->proc_request(handle, cut->proc_id)) { + printf("%s: requesting primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->set_device_resets(handle, cut->dev_id, 0x3)) { + printf("%s: module and local reset primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->idle_device(handle, cut->dev_id)) { + printf("%s: putting primary core into retention failed\n", __func__); + return -EINVAL; + } + + return 0; +} + +int deprepare_lbist(struct ti_sci_handle *handle) +{ + struct ti_sci_proc_ops *proc_ops = &handle->ops.proc_ops; + struct ti_sci_dev_ops *dev_ops = &handle->ops.dev_ops; + struct lbist_inst_info *info_lbist = k3_bist_priv->lbist_info; + struct core_under_test *cut = &info_lbist->cut; + + if (dev_ops->put_device(handle, 0)) { + printf("%s: power off secondary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->put_device(handle, cut->dev_id)) { + printf("%s: power off primary core failed\n", __func__); + return -EINVAL; + } + + lbist_disable_isolation(); + + if (dev_ops->idle_device(handle, cut->dev_id)) { + printf("%s: retention primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->idle_device(handle, 0)) { + printf("%s: retention secondary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->put_device(handle, 0)) { + printf("%s: power off secondary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->put_device(handle, cut->dev_id)) { + printf("%s: power off primary core failed\n", __func__); + return -EINVAL; + } + + if (dev_ops->set_device_resets(handle, cut->dev_id, 0)) { + printf("%s: putting primary core out of local reset failed\n", __func__); + return -EINVAL; + } + + if (proc_ops->proc_release(handle, cut->proc_id)) { + printf("%s: release primary core failed\n", __func__); + return -EINVAL; + } + + 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; + struct k3_bist_privdata *priv = dev_get_priv(dev); + struct pbist_inst_info *info; + struct lbist_inst_info *info_lbist; + void *reg; + + debug("%s(dev=%p)\n", __func__, dev); + + priv = dev_get_priv(dev); + priv->dev = dev; + + k3_bist_priv = priv; + + reg = dev_read_addr_name_ptr(dev, "cfg"); + if (!reg) { + dev_err(dev, "No reg property for BIST\n"); + return -EINVAL; + } + priv->pbist_base = reg; + + reg = dev_read_addr_name_ptr(dev, "ctrl_mmr"); + if (!reg) { + dev_err(dev, "No reg property for CTRL MMR\n"); + return -EINVAL; + } + priv->lbist_ctrl_mmr = reg; + + ret = dev_read_u32(dev, "ti,sci-dev-id", &priv->instance); + if (!priv->instance) + return -ENODEV; + + switch (priv->instance) { + case PBIST14_DEV_ID: + priv->pbist_info = &pbist14_inst_info; + priv->lbist_info = &lbist_inst_info_main_r5f2_x; + info = priv->pbist_info; + info_lbist = priv->lbist_info; + priv->intr_num = info->intr_num; + break; + default: + dev_err(dev, "%s: PBIST instance %d not supported\n", __func__, priv->instance); + return -ENODEV; + }; + + return 0; +} + +static const struct bist_ops k3_bist_ops = { + .run_lbist = k3_run_lbist, + .run_lbist_post = k3_run_lbist_post, + .run_pbist = k3_run_pbist, + .run_pbist_post = k3_run_pbist_post, + .run_pbist_neg = k3_run_pbist_neg, + .run_pbist_rom = k3_run_pbist_rom, +}; + +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, + .ops = &k3_bist_ops, + .probe = k3_bist_probe, + .priv_auto = sizeof(struct k3_bist_privdata), +}; |