/*
* PVA uCode Self Test
*
* Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include "dev.h"
#include "pva.h"
/* Defines for self test-mode in ucode */
#define PVA_MBOX_VAL_TESTS_DONE 0x57800000
#define PVA_SELF_TESTMODE_START_ADDR 0x90000000
#define PVA_SELF_TESTMODE_ADDR_SIZE 0x00800000
int pva_run_ucode_selftest(struct platform_device *pdev)
{
struct nvhost_device_data *pdata = platform_get_drvdata(pdev);
struct pva *pva = pdata->private_data;
int err = 0;
u32 reg_status;
u32 ucode_mode;
void *selftest_cpuaddr;
dma_addr_t base_iova = PVA_SELF_TESTMODE_START_ADDR;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
struct dma_attrs attrs;
init_dma_attrs(&attrs);
#else
unsigned long attrs = 0;
#endif
/* Map static memory for self test mode */
nvhost_dbg_info("uCode TESTMODE Enabled");
dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, __DMA_ATTR(attrs));
dma_set_attr(DMA_ATTR_SKIP_IOVA_GAP, __DMA_ATTR(attrs));
selftest_cpuaddr = dma_alloc_at_attrs(&pdev->dev,
PVA_SELF_TESTMODE_ADDR_SIZE, &base_iova,
GFP_KERNEL|__GFP_ZERO, __DMA_ATTR(attrs));
if (!selftest_cpuaddr) {
dev_warn(&pdev->dev, "Failed to get Selftest Static memory\n");
err = -ENOMEM;
goto err_selftest;
}
pva->mailbox_status = PVA_MBOX_STATUS_WFI;
host1x_writel(pdev, hsp_ss0_set_r(), PVA_TEST_RUN);
/* Wait till we get a AISR_ABORT interrupt */
err = pva_mailbox_wait_event(pva, 60000);
if (err)
goto wait_timeout;
ucode_mode = host1x_readl(pdev, hsp_ss0_state_r());
/*Check whether ucode halted */
if ((ucode_mode & PVA_HALTED) == 0) {
nvhost_dbg_info("uCode SELFTEST Failed to Halt");
err = -EINVAL;
goto err_selftest;
}
reg_status = pva_read_mailbox(pdev, PVA_MBOX_ISR);
/* check test passed bit set and test status done*/
if ((ucode_mode & PVA_TESTS_PASSED) &&
(reg_status == PVA_MBOX_VAL_TESTS_DONE))
nvhost_dbg_info("uCode SELFTEST Passed");
else if (ucode_mode & PVA_TESTS_FAILED)
nvhost_dbg_info("uCode SELFTEST Failed");
else
nvhost_dbg_info("uCode SELFTEST UnKnown State");
/* Get CCQ8 register value */
reg_status = host1x_readl(pdev, cfg_ccq_status8_r());
nvhost_dbg_info("Major 0x%x, Minor 0x%x, Flags 0x%x, Trace Sequence 0x%x \n",
(reg_status & 0xFF000000) >> 24,
(reg_status & 0x00FF0000) >> 16,
(reg_status & 0xFF00) >> 8,
(reg_status & 0xFF));
wait_timeout:
err_selftest:
if (selftest_cpuaddr)
dma_free_attrs(&pdev->dev,
PVA_SELF_TESTMODE_ADDR_SIZE, selftest_cpuaddr,
PVA_SELF_TESTMODE_START_ADDR, __DMA_ATTR(attrs));
return err;
}