808 lines
22 KiB
C
808 lines
22 KiB
C
// 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),
|
|
};
|